September 12, 2022 python imports pain ☕️ buy me a coffee
Any budding python program has been there. You’ve just made a wonderful new project with an amazingly descriptive file structure! Well done you!
foo
├── bar
│ ├── bar.py
│ └── __init__.py
└── __init__.py
Now, foo/__init__.py is empty making foo a module, and since foo/bar also has a __init__.py file, it is a submodule. For the purposes of this little demonstration, the files are as follows:
# foo/bar/__init__.py
from .bar import bar
# foo/bar/bar.py
"""
This is a really important module!
"""
def bar():
print("Hello, World!")
Everything works real nicely except you find yourself needing to call help() on the bar sub-submodule (i.e. foo.bar.bar not foo.bar.bar.bar). How do we do this?
>>> from foo.bar import bar
>>> help(bar)
Help on function bar in module foo.bar.bar:
bar()
Well, that was expected right? Let’s try something different…
>>> import foo.bar.bar
>>> help(foo.bar.bar)
Help on function bar in module foo.bar.bar:
bar()
Shoot! Same again.
How about…
>>> import foo.bar as b
>>> help(b.bar)
Help on function baz in module foo.bar.bar:
baz()
You see what’s going on here?
Because we’ve named our function the same as the submodule(yes, bar.py is being treated as a submodule within the submodule bar), and we’re OVERWRITING the submodule’s name in foo/bar/__init__.py, it’s impossible to access anything within the submodule other than bar(). However, with an empty init file, we could have called help on the submodule as:
>>> from foo.bar import bar
>>> help(bar)
Help on module foo.bar.bar in foo.bar:
NAME
foo.bar.bar - This is a really import module!
FUNCTIONS
bar()
FILE
foo/bar/bar.py
__init__.py file if possiblebar, then name the file _bar.py and the function something a little more creative such as BarAnd another top tip, make good use of the __all__ variable.