Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are absolute imports possible from within a subpackage?

There's something that's bothering me about imports in packages. Imagine I have the following directory structure:

pack
├── __init__.py
├── sub1
│   ├── __init__.py
│   └── mod1.py
└── sub2
    ├── __init__.py
    └── mod2.py

Inside mod1.py I have the following code to import mod2.py:

# mod1.py
import pack.sub2.mod2
pack.sub2.mod2.helloworld()

I have a main.py file in the directory containing pack that imports pack/sub1/mod1.py

How does mod1.py have access to pack? pack is not in the same directory as mod1.py. Does python automatically add the topmost package to sys.path?

like image 965
asad Avatar asked Oct 20 '22 04:10

asad


1 Answers

You can investigate this by inspecting sys.path in an interactive interpreter. What you'll find is that the first element of it is the location of the script the interpreter was told to run. This means that when you run your script at the top level (the location of the pack package), that location is added to sys.path automatically. It doesn't have anything to do with the actual package structure, so if you ran mod1.py as a script you would have things break (this is probably why you put your script at the top level!).

Note that in Python 2, you also have the issue of implicit relative imports, which doesn't impact the issue you're asking about, but might come up if you had a few more modules involved. If you added mod3.py to sub1, you could import it from mod1 with just import mod3, with the pack.sub1 prefix being figured out implicitly. This implicit behavior is generally considered a bad thing, and in Python 3 such implicit relative imports are not allowed (you can also disable them in Python 2 with from __future__ import absolute_import). To import pack.sub1.mod3 from pack.sub1.mod1 you'd need to either name it in full, or use an explicit relative import: from . import mod3

To tie this relative import business back to your question, if you wanted to avoid relying on pack being part of sys.path (or, more realistically, protect against changes to pack's name), you could modify your import of mod2 from mod1 to be an explicit relative import. Just use from .. import sub2.mod2.

like image 56
Blckknght Avatar answered Oct 22 '22 18:10

Blckknght