Python import precedence: packages or modules?
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
.
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.
from a python shell:
from foo import bar
print bar.__file__
should tell you which file has been imported
Rob