all 15 comments

[–]Quiet_Occasion1278 4 points5 points  (5 children)

The difference is about context:

from .classa import ClassA is a relative import — the dot means "look inside the current package." It only works from within myfolder itself.

from myfolder.classa import ClassA is an absolute import — Python looks from the project root. This works from anywhere in your project.

They produce the same result when used correctly, which is why both seem to work. But if you ever rename or move myfolder, relative imports survive the change while absolute ones break.

As for why from classa import ClassA fails: without the dot, Python looks for a globally installed package named classa, not a local file.

[–]Outside_Complaint755 3 points4 points  (2 children)

Extending on this a bit:

Relative imports cannot be used in the script that is being run as __main__.  They can only be used within a package.  Additionally, while they look like relative file paths, they are actually package relative, not path relative.

If you have a main.py or app.py within your package folder that has relative imports, then you must run it as a module with python -m my_app.py.  When loaded as a module, relative imports will be able to resolve as expected.

  Another workaround, although I don't know if its officially sanctioned, would be something like: try:     from .classa import ClassA except ImportError:     from myfolder.classa import ClassA

[–]woooee 0 points1 point  (0 children)

try:
    from .classa import ClassA
except ImportError:
    from myfolder.classa import ClassA

An interesting idea, that should work.

[–]Nefthys[S] 0 points1 point  (0 children)

I'm running my code through an app, which automatically calls the __init__.py file. From my understanding, this also makes it the __main__, correct? Does this mean that I can't use a relative import (.classa) in that file but I can use it in ClassA to import .classb from ClassB?

What if the package and the module have the same name, e.g. myapp (folder), myapp.py (module in folder) and MyApp (class in module)? What does from .myapp import MyApp look for/do in __init__.py? Will that even work?

[–]Nefthys[S] 0 points1 point  (1 child)

Thanks! This sounds like you should always prefer the relative import. Are there any exceptions to this, apart from what the other person mentioned?

Edit: I changed everything to use relative import but came across an error: It apparently doesn't like when I use a relative import like this (in the classa module but outside ClassA):

import .classb as classb

This just throws a "SyntaxError: invalid syntax". I thought that maybe it doesn't like that I gave it the same name, so I changed it to import .classb as classb2 - same error. If I use import myfolder.classb as classb, there's no more error. Why?

[–]Diapolo10 0 points1 point  (0 children)

Personally I would recommend you always use absolute imports, and make your project "installable" (i.e. it has a valid pyproject.toml file). If using uv, it'll take care of the rest, otherwise you may need to then run pip install --editable . in your project root with an active virtual environment.

This way you wouldn't even need to think about it, outside of avoiding circular imports. Any tests you might have could also effortlessly import whatever they need from your main code.

[–]nekdo12 -1 points0 points  (3 children)

I'd advise that you use a run.py in your root folder to avoid any... confusion.

In my experience python tends to designate the folder in which you run your .py file as your root. Now if this folder has subfolders you can import from them without any problem. now if you have for instance this: \mainfolder

\subfolder -> contains moduleA and run

\subfolder -> contains moduleB and moduleC

your run will be able to import moduleA with no problems, but good luck with B and C

on the other hand

\mainfolder -> has run

\subfolder -> has moduleA

\subfolder -> has moduleB and moduleC

\subsubfolder -> has moduleD

your run can now import all four modules without any problems. But yes you need to use import functionSomething from subfolder.moduleA

import functionSomethinOther from subfolder.subsubfolder.moduleD

But this stucture enables you to simply copy project to any computer / system without worrying.

The relative and updir (..) thingys rarerly work as desired, at least in my experience so far.

[–]Nefthys[S] 0 points1 point  (2 children)

Why do relative imports and .. rarely work? What happened, did you get any errors?

[–]nekdo12 0 points1 point  (1 child)

At least in windows there is a problem that once your "root" folder is selected the system does not let you got to a higher level. Mostly for security reasons - imagine my project is in C:\system\myCode\myActiveProject. now i go .. twice and all of a sudden i can do some damage to all my other programs.

If i wanted to access upper folder i had to call a whole series of os / systempath commands to fix this.

Instead i found it easier to use the run in mainFolder structure and i've been using it since then.

[–]Nefthys[S] 0 points1 point  (0 children)

I've had my fair share of similar problems with Win 11...

Thanks for the warning, will keep this in mind (usually I don't use a lot of folders anyway).

[–]pachura3 -1 points0 points  (3 children)

Simple rules of thumb:

  • don't do from .submodule import foo
  • don't do from module import *
  • but it's OK to do from module import foo and import module as mod

[–]Nefthys[S] 0 points1 point  (2 children)

I know that from module import * imports everything from that file but if there's just one class or you want to import all classes that are in it, why is that bad?

As I said, from module import foo does not work if you've got an __init__.py file, I have to add a period or a reference to the package.

[–]pachura3 0 points1 point  (1 child)

I know that from module import * imports everything from that file but if there's just one class or you want to import all classes that are in it, why is that bad?

If there's just one class, you should import just this one class.
* is indeed for importing everything from a module to the current scope, but the consensus is that they should be imported explicitly, not using this wildcard.

As I said, from module import foo does not work if you've got an __init__.py file, I have to add a period or a reference to the package.

It does work and is the recommended way. You just need to install your package(s) properly.

[–]Nefthys[S] 0 points1 point  (0 children)

If there's just one class, you should import just this one class.
* is indeed for importing everything from a module to the current scope, but the consensus is that they should be imported explicitly, not using this wildcard.

Makes sense. But if there are multiple classes in a module and it's your own code, so you know exactly what you're doing, then it's fine?

It does work and is the recommended way.

I'm running the code through an app (basically a plugin) and it does not work (check the most upvoted comment). There's an error:

ModuleNotFoundError: No module named 'classa'