直到今天我才注意到一些包上定义的__path__
特殊属性。根据文档:
包支持一个或多个特殊属性,
__path__
就是其中之一。它被初始化为一个列表,其中包含在执行文件中的代码之前,持有包的__init__.py
文件的目录名称。这个变量可以被修改,并影响对于包中包含模块和子包的未来搜索。虽然这个功能并不经常需要使用,但它可以用来扩展找到的模块集合。
有人能向我解释一下这是什么意思,以及为什么我需要使用它吗?
通常与pkgutil一起使用,以使软件包在磁盘上分布。例如,zope.interface和zope.schema是单独的发行版(zope
是一个“命名空间包”)。您可能已经在/usr/lib/python2.6/site-packages/zope/interface/
中安装了zope.interface,而在/home/me/src/myproject/lib/python2.6/site-packages/zope/schema
中更局部地使用zope.schema。
如果将pkgutil.extend_path(__path__, __name__)
放置在/usr/lib/python2.6/site-packages/zope/__init__.py
中,则可以导入zope.interface和zope.schema,因为pkgutil将更改__path__
为['/usr/lib/python2.6/site-packages/zope', '/home/me/src/myproject/lib/python2.6/site-packages/zope']
。
pkg_resources.declare_namespace
(Setuptools的一部分)类似于pkgutil.extend_path
,但它更加了解路径上的zip文件。
手动更改__path__
不常见,也可能不必要,尽管查看命名空间包时调试导入问题非常有用。
您还可以通过创建一个文件distutils/__init__.py
并将其提前添加到sys.path
中进行猴子补丁,例如,我有时会对distutils进行猴子补丁:
import os
stdlib_dir = os.path.dirname(os.__file__)
real_distutils_path = os.path.join(stdlib_dir, 'distutils')
__path__.append(real_distutils_path)
execfile(os.path.join(real_distutils_path, '__init__.py'))
# and then apply some monkeypatching here...
如果你改变 __path__
,你可以强制解释器在不同的目录中查找属于该包的模块。
这将允许您根据运行时条件加载相同模块的不同版本。如果您想在不同平台上使用相同功能的不同实现,可以这样做。
commands = {name: 'django.core' for name in find_commands(__path__[0])}
- Kevin S Linmypkg
和_mypkg_foo
。
- _mypkg_foo
包含可选模块foo.py
到mypkg
中。
- 在下载和安装时,mypkg
不包含foo.py
。
mypkg
的__init__.py
可以像这样做:try:
import _mypkg_foo
__path__.append(os.path.abspath(os.path.dirname(_mypkg_foo.__file__)))
import mypkg.foo
except ImportError:
pass
_mypkg_foo
,那么mypkg.foo
对他们是可用的。如果没有安装,则不存在。import mypkg.foo
的意义是什么? - codeforester__path__.append(os.path.join(os.path.dirname(__file__), "utils"))
views/__init__.py
文件的更改,我可以在不对其他文件进行进一步更改的情况下,使用新的文件结构运行软件的其余部分。views/__init__.py
文件中使用import
语句进行类似操作,但是子包模块仍然无法通过view
包的导入可见 - 我不确定是否有遗漏;欢迎对此进行评论!)