Python import precedence: packages or modules?
I wasn't clear how to correctly name this question.
Case 1
Assume that I have the following directory structure.
foo
|
+- bar/__init__.py
|
+- bar.py
If I have
from foo import bar
How do I know which bar (bar.py
or bar/__init__.py
) is being imported? Is there any easy way to automatically detect this from occurring?
Case 2
foo
|
+- foo.py
|
+- other.py
If other.py has the line
import foo
How do I know which foo (foo or foo.foo) is being imported? Again, is tehre any easy way to automatically detect this from occurr开发者_Go百科ing?
TLDR; a package takes precedence over a module of the same name if they are in the same directory.
From the docs:
"When a module named
spam
is imported, the interpreter searches for a file namedspam.py
in the current directory, and then in the list of directories specified by the environment variablePYTHONPATH
. This has the same syntax as the shell variable PATH, that is, a list of directory names."
This is a bit misleading because the interpreter will also look for a package called spam
(a directory called spam
containing an __init__.py
file). Since the directory entries are sorted before searching, packages take precedence over modules with the same name if they are in the same directory because spam
comes before spam.py
.
Note that "current directory" is relative to the main script path (the one where __name__ == '__main__' is True
). So if you are at /home/billg
calling /foo/bar.py
, "current directory" refers to /foo
.
from a python shell:
from foo import bar
print bar.__file__
should tell you which file has been imported
Rob
Packages (directories with __init__.py
) take precedence over modules. The documentation of this fact is difficult to find but you can see this in the source: python 2.7, python 3.6 (thanks @qff for the find).
You will also need a __init__.py
within the foo directory for your example to work.
If other.py
is inside of foo/
then it will load foo.py
(not the directory foo/
) because it will look in the current directory first (unless you've played with PYTHONPATH or sys.path).
I would like to complement the accepted answer. For Python 3.3+
, namespace packages have been introduced and the import order according to PEP 420 follows:
During import processing, the import machinery will continue to iterate over each directory in the parent path as it does in Python 3.2. While looking for a module or package named
"foo"
, for each directory in the parent path:
- If
<directory>/foo/__init__.py
is found, a regular package is imported and returned.- If not, but
<directory>/foo.{py,pyc,so,pyd}
is found, a module is imported and returned. The exact list of extension varies by platform and whether the-O
flag is specified. The list here is representative.- If not, but
<directory>/foo
is found and is a directory, it is recorded and the scan continues with the next directory in the parent path.- Otherwise the scan continues with the next directory in the parent path.
If the scan completes without returning a module or package, and at least one directory was recorded, then a namespace package is created.
in the first case you're trying to import the function bar from file 'foo.py'
In the second you're trying to import the file 'foo.py'
精彩评论