所以 python 路径的行为与 PERL5LIB 不同,这使得将库划分到不同的 repos 中有点困难。 让我描述一下它在 PERL 中是如何工作的:
如果目录结构如下:
项目/lib/bar/foo.pm
common/lib/bar/baz.pm
现在 PERL5LIB 设置为 'project/lib:common/lib'
在我的 perl 脚本中我可以这样做:
use bar::foo; # this comes from project/lib/bar/foo.pm
use bar::baz; # this comes from common/lib/bar/baz.pm
在 Python 中,虽然具有相同的目录结构(使用 .py 文件代替)并将相同的目录添加到 PYTHONPATH(当然,在 project/lib/bar 和 common 中添加虚拟 __init__.py
/lib/bar 目录):
import bar.foo # this successfully imports from project/lib/bar/foo.py
import bar.baz # this fails!
在 Python 中是否有解决此问题的方法,因为这会使分区代码成为一场噩梦。
编辑:更清楚 __init__.py
文件的位置。
最佳答案
您的第一个问题是您试图将 Perl 范式强加到 Python 中。您的第二个问题是您似乎不了解 Python namespace 系统的工作原理。您不能将同一个包导入全局命名空间两次。它只是不能那样工作。
Python 将使用它找到的第一个匹配项。因为当您从第一个位置导入 bar.foo
时它找到包 bar
,所以当您尝试导入 bar.baz< 时它甚至不会尝试后者
位于后一个位置。
当您导入一个模块时,它会被添加到全局命名空间中,并且还会在 sys.modules
字典中进行跟踪。从一个新的 Python 解释器开始,如果你导入 sys
,你会看到它在全局命名空间中:
>>> import sys
>>> globals().keys()
['__builtins__', '__name__', 'sys', '__doc__', '__package__']
如果通过key获取,则获取模块对象:
>>> globals()['sys']
<module 'sys' (built-in)>
现在,如果您导入 foo
,您会看到它也最终出现在全局命名空间中:
>>> import foo
>>> globals().keys()
['__builtins__', '__package__', 'sys', '__name__', 'foo', '__doc__']
还有 sys.modules
:
>>> sys.modules['foo']
<module 'foo' from 'foo.pyc'>
>>> globals()['foo']
<module 'foo' from 'foo.pyc'>
即使您从全局命名空间中删除了 foo
,它仍然驻留在 sys.modules
中:
>>> del foo
>>> 'foo' in globals()
False
>>> 'foo' in sys.modules
True
这是为什么?将 sys.modules
视为已导入模块的注册表。这是作为一种优化完成的,因此如果您导入同一包的多个部分,已经加载的部分不会继续重新加载。真正“卸载”模块的唯一方法是将其从 sys.modules
和全局命名空间中删除。
我希望通过说明这一点,您还可以看到每个包或模块对象只能在任何给定程序的命名空间中驻留一次。这就是您尝试做的事情失败的原因。 Python 已经在第一次成功导入了 bar
,因此它不会再次尝试重新导入它。
如果您真的希望两个具有相同包名的不同路径驻留在文件系统中的不同位置,您应该研究 Python 的 namespace packages .这将允许您在将自身绑定(bind)到另一个包的 namespace 的备用位置安装包。
另见:
关于python - PYTHONPATH 与 PERL5LIB 的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5723998/