Why python finds module instead of package if they have the same name?

拈花ヽ惹草 提交于 2019-11-29 04:11:45

I simplified the example from the question to demostrate that only four solutions are possible:

  • Explicit relative import from . import some_module or with more commas from ..
  • Relative import (without "xyz." if used in the package "xyz")
  • Absolute import using from __future__ import absolute_import (or use Python 3)
  • Never repeat the top level importable name of the package in any path inside it.

What solution is the best? It depends on personal preference of Python 2 or 3. Only the last one is nice and universal for all Pythons. It was really a useful question.


xyz/tests/__init__.py: import xyz.tests.t

xyz/tests/t.py:

import sys
print('sys.path = %s' % sys.path) # see that the parent of "xyz" is on sys.path
print("importing xyz.tests")
import xyz.a

xyz/a.py:

# solution A: absolute_import by __future__  (or use Python 3)
#from __future__ import absolute_import
print("importing xyz.a")
# solution B: explicit relative import
#from . import b    # and remove "import xyz.b"
# solution C: relative import (not recommended)
#import b           # and remove "import xyz.b"
import xyz.b

xyz/b.py: print("imported xyz.b")

xyz/xyz.py: print("Imported xyz.xyz !!!")

xyz/__init__.py: empty file


Everything possible fails, e.g.

parent_of_xyz=...  # The parent directory of "xyz" - absolute path
cd $parent_of_xyz
python -m xyz.tests.t
PYTHONPATH=$parent_of_xyz/xyz python -m unittest tests
PYTHONPATH=$parent_of_xyz     python xyz/tests/t.py

with messages like

Imported xyz.xyz  !!!
...
ImportError...

If any solution is applied (uncommented), all three examples work.

It can be more simplified without using any subdirectory.

EDIT: I tried yesterday many tests but I wrote it inconsitently from different versions. Excuse me that it was unreproducible from the answer. Now it is fixed.

Do not modify sys.path it leads to the issues when the same module is available under different names. See Traps for the Unwary.

Use absolute or explicit relative imports instead in the code and run your scripts from the project directory. Run the tests using the full name:

$ python -munittest root.tests.test_1

Some packages do modify sys.path internally e.g., see how twisted uses _preamble.py or pypy's autopath.py. You could decide whether their downsides (introduction of obscure import problems) are worth the convience (more ways to run your scripts are allowed). Avoid modifying sys.path in a code that is used as a library i.e., limit it to test modules and your command-line scripts.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!