PYTHONPATH与PERL5LIB的行为

时间:2011-04-19 23:39:24

标签: python perl

因此,python路径的行为与PERL5LIB不同,这使得将库分区到不同的存储库中变得有点困难。 让我描述它在PERL中的工作原理:

如果目录结构如下:

项目/ LIB /酒吧/ foo.pm
的common / lib /酒吧/ 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(当然在项目/ lib / bar和common / lib / bar目录中添加虚拟__init__.py ):

import bar.foo # this successfully imports from project/lib/bar/foo.py
import bar.baz # this fails!

在Python中有没有解决方法,因为这会使分区代码变成一场噩梦。

编辑:更清楚地了解__init__.py文件的位置。

1 个答案:

答案 0 :(得分:3)

你的第一个问题是你正试图强迫Perl范例进入Python。您的第二个问题是您似乎不了解Python命名空间系统的工作原理。您不能将相同的包导入两次到全局命名空间。它只是不起作用。

Python将使用它找到的第一个匹配项。由于当您从第一个位置导入bar时它找到了包bar.foo,因此当您尝试导入位于后一位置的bar.baz时,它甚至都不会尝试后者。

导入模块时,它会添加到全局命名空间,并在sys.modules字典中进行跟踪。从新的Python解释器开始,如果导入sys,您会看到它在全局命名空间中:

>>> import sys
>>> globals().keys()
['__builtins__', '__name__', 'sys', '__doc__', '__package__']

如果按键获取,则会获得模块对象:

>>> 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和全局命名空间中删除它。

我希望通过说明这一点,您还可以看到每个包或模块对象只能在任何给定程序的命名空间中驻留ONCE。这就是为什么你要做的就是失败。 Python已经第一次成功导入bar,所以它不会再次尝试重新导入它。

如果你真的想要两个具有相同包名的不同路径驻留在文件系统的不同位置,你应该研究Python的namespace packages。这将允许您在备用位置安装包,这些包将自己绑定到另一个包的命名空间。

另见: