__path__对什么有用?

Jas*_*ker 53 python module path

我从来没有注意到__path__今天之前在我的某些软件包上定义的属性.根据文件:

包支持另一个特殊属性__path__.这被初始化为一个列表,其中包含在__init__.py执行该文件中的代码之前保存包的目录的名称.这个变量可以修改; 这样做会影响将来对包中包含的模块和子包的搜索.

虽然通常不需要此功能,但它可用于扩展程序包中的模块集.

有人可以向我解释这究竟是什么意思以及为什么我会想要使用它?

Syn*_*tic 32

如果更改__path__,则可以强制解释器在属于该包的模块的不同目录中查找.

这将允许您根据运行时条件加载相同模块的不同版本.如果要在不同平台上使用相同功能的不同实现,则可以执行此操作.


Ian*_*ing 32

这通常与pkgutil一起使用,以便在磁盘上布置包.例如,zope.interface和zope.schema是单独的发行版(zope是"命名空间包").你可能安装了zope.interface /usr/lib/python2.6/site-packages/zope/interface/,而你在本地使用zope.schema /home/me/src/myproject/lib/python2.6/site-packages/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但更了解路径上的拉链.

手动更改__path__是不常见的,可能不是必需的,但在调试命名空间包的导入问题时查看变量很有用.

你也可以用__path__monkeypatching,例如,我有时通过创建一个distutils/__init__.py早期的文件monkeypatched distutils sys.path:

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...
Run Code Online (Sandbox Code Playgroud)

  • 我有一种感觉,它与命名空间包有关,但我在拼凑它的工作原理时遇到了问题。谢谢! (2认同)

Mat*_*son 7

除了根据运行条件选择不同版本的模块,如Syntactic所说,此功能还允许您将包拆分为多个部分/下载/安装,同时保持单个逻辑包的外观.

考虑以下.

  • 我有两个包,mypkg_mypkg_foo.
  • _mypkg_foo包含可选模块mypkg,foo.py.
  • 如下载和安装,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
Run Code Online (Sandbox Code Playgroud)

如果有人安装了包_mypkg_foo,那么mypkg.foo他们就可以使用.如果他们没有,它就不存在.

  • `import mypkg.foo` 在这里有什么意义? (2认同)

Gra*_*yne 6

我遇到的一个特殊情况是,当一个包变得足够大时,我想将其部分拆分到子目录中,而不必更改引用它的任何代码。

例如,我有一个名为的包views,它收集了许多支持实用程序函数,这些函数与该包的主要顶级用途混淆了。我能够将这些支持功能移动到子目录中utils,并将以下行添加到__init__.py包中views

__path__.append(os.path.join(os.path.dirname(__file__), "utils"))
Run Code Online (Sandbox Code Playgroud)

也有了这个改变views/__init_.py,我可以使用新的文件结构运行软件的其余部分,而无需对文件进行任何进一步的更改。

import(我尝试对文件中的语句执行类似的操作views/__init__.py,但是通过导入子包模块仍然不可见view- 我不完全确定我是否遗漏了其中的某些内容;欢迎发表评论!)

(此响应基于Python 2.7安装)