Can modules with a common package hierarchy mentioned multiple times in my PYTHONPATH?
I have two separate projects that share a package name. They run OK as long as they are not both on the PYTHONPATH, but as soon as they both ap开发者_StackOverflow社区pear one of them cannot find imports in its own project.
Example, two projects like this:
Project 1:
x/
__init__.py
test.py
foo.py
test.py contains the line:
import x.foo
Project 2:
x/
__init__.py
bar.py
If I run
PYTHONPATH=. python x/y/test.py
there is no error. But if I run
PYTHONPATH='pathtoproject2:.' python x/test.py
I get the error:
Traceback (most recent call last):
File "x/test.py", line 1, in <module>
import x.foo
ImportError: No module named foo
Is there a way to have different Python projects with a common package share the PYTHONPATH? Or will Python always use only the first path where a package is found?
Note: I know if you modify the import from x.foo to import foo then it will work. But I want to know if it is possible to do it without modifying either package.
Although not supported natively by the import mechanism, there is a workaround solution to create namespaced packages in python. You just have to put the following code on both __init__.py files.
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
pkg_resources is provided by setuptools python package and has the advantage that also handles packages contained within egg zip files.
pkgutil is contained in python's standard library so we rely on it to handle the namespace extension if setuptools is not installed in the system.
for more information about python namespace packages can be found here:
http://packages.python.org/distribute/setuptools.html#namespace-packages
http://www.python.org/dev/peps/pep-0382/
Currently, Python does not support packages from different directories. A package is an unit, not just a namespace. This is different from Java "packages" or the more appropriately named "namespaces" in .NET.
When importing a package, Python will scan sys.path
, sequentially, and use the first match. If there is another module or package with a matching name in a directory that appears later in the path, it won't be found.
Your "note" is not true, by the way. When you use import foo
, Python will try a relative import within the directory of test.py
, find no match, then attempt an absolute import of module foo
, which does not exist either, and then raise an ImportError
.
Instead of using package names to group modules using a common prefix, think of packages as smallish, self-contained libraries. In Python, flat is better than nested, and it is preferable to have multiple top-level packages, each fulfilling one distinct purpose, than having one large monolithic package. Instead of org.example.foo
and org.example.bar
, just use foo
and bar
.
精彩评论