0

I have a simple example project with these files:

folder
    __init__.py
    foo.py
    foobar.py
    script.py

In foobar.py the function foo is imported with from .foo import foo.
(It is then used in the function foobar).
In script.py the function foobar is imported with from .foobar import foobar.
(It is then executed.)

But putting the dots in the import statement is not always the right choice.
Depending on how the script is run, their presence can cause:
ImportError: attempted relative import with no known parent package
Or their absence can cause:
ModuleNotFoundError: No module named 'foobar'

The code can be found on GitHub. (There is also the same with absolute paths.)

with dots

This works for the two usecases that I need:

  • run script using the m-switch: python -m project.folder.script
  • import foobar in the Python console: from project.folder.foobar import foobar

This screenshot shows how running the script works with and fails without the m-switch:

overview with dots

without dots

Gladly there is no need to run the script without the m-switch.
(Although it would be nice, because the IDE has a button for that.)

This screenshot shows how running the script fails with and works without the m-switch:

enter image description here

paths in detail

It seems worthwhile to take a closer look at __name__ and __file__ in all cases.
__name__ of _script.py is always the string '__main__'.

enter image description here

conclusion

Apparently for me this just boils down to having to use the dot and the m-switch.
(This is just mildly annoying, because my IDE does not have auto-completion for it.)

But I would still like to understand, why there are these two ways of doing essentially the same thing. People often say, that the dot is for going up a directory (like ../ in HTML and PHP).
But there is something wrong with that, because the location is the same in both cases.
(We just talk about neighboring files in the same folder.)

This must be far from the first question about this topic.
I hope it is clear enough to compensate for that redundancy.

Watchduck
  • 1,076
  • 1
  • 9
  • 29
  • 1
    Does this answer your question? [Relative imports for the billionth time](https://stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time) – Brian61354270 Jul 13 '23 at 11:34
  • 1
    If you want to understand relative imports, you have to stop thinking in terms of folders and files and start thinking in terms of packages and modules. – chepner Jul 13 '23 at 19:58

1 Answers1

1

Let me explain why the dot is useful and when its used.

  1. The dot is really useful when you are creating more complex projects (like a website using Django or flask).

  2. The simplest way to I would explain the dot in front of imports is that it basically adds the file directory into your codes import directories, let me explain.

your current directory when you are importing through script.py is: folder.

Why without dot it works: If you don't have the dot in front of your import, you are basically telling Python to import foo.py from the same directory as your script.py

Why using dot it throws an error: Because you don't use a main.py to run your code (the main file would be outside of your folder but in the same directory). Python considers your script.py as your __main__, This means that you cannot use the dot in imports that are in your script.py. This is because you haven't told Python which is the file/folder from which to import foobar.

If you would have a main.py, when importing the line from .foobar import foobar you are basically writing the line: from folder.foobar import foobar. Which would be correct.

Note: (This would require you to write import folder inside your main.py, and write from . import script inside your __init__.py)

for your code, don't use the dot in front of imports and don't use the m-switch.

I suggest that you could make a main.py in the same directory as your folder, this would make it possible for you to create a more complex script without a big headache later on. (In this case you have to add the dot in all of your code inside the folder)

Sup
  • 11
  • 2
  • I meant main.py as in the file that you will be using to run the script, you can name it whatever you want I just used main.py. Sorry for not clarifying. – Sup Jul 13 '23 at 14:04
  • It may take a while until I wrap my mind around this. :D Note, that there are two requirements: I want to run the script, but I also want to import foobar in the console. I am not sure that would work without the dot. – Watchduck Jul 13 '23 at 14:15
  • In that case you should use the method i suggested with the main.py. – Sup Jul 13 '23 at 14:29
  • Gladly I don't have to solve a real problem here, as I see no downside to the m-switch. The aim is just to bring more light into this confusing topic. I have modified the code to print the `__name__` and `__file__` variables in all cases. Would you say, that something relevant can be deduced from them? Are there other variables, that might be useful? – Watchduck Jul 13 '23 at 20:56
  • The prints definitely bring clarity to how Python handles relative imports. In my opinion, the best way to become good at this is by exercise. By using breakpoints and reading error messages you can save the hassle of logging every action when you debug. – Sup Jul 14 '23 at 10:17