2010-04-23 73 views
42

我從未注意到今天之前在我的一些軟件包中定義的__path__屬性。根據文檔:__path__對於什麼有用?

軟件包支持一個更特別的 屬性,__path__。這是 已初始化爲包含 的列表,其中包含 程序包的__init__.py之前的代碼 的目錄的名稱被執行。這個 變量可以被修改;這樣做 影響將來搜索模塊 和包含在 包中的子包。

雖然此功能通常不需要 ,但它可用於擴展包中的 模塊集。

有人可以向我解釋這是什麼意思,爲什麼我會想要使用它?

回答

22

這通常與pkgutil用來讓一個封裝在磁盤進行佈局。例如,zope.interface和zope.schema是獨立的發行版(zope是「命名空間包」)。您可能在/usr/lib/python2.6/site-packages/zope/interface/中安裝了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將不得不['/usr/lib/python2.6/site-packages/zope', '/home/me/src/myproject/lib/python2.6/site-packages/zope']變化__path__

pkg_resources.declare_namespace(Setuptools的一部分)與pkgutil.extend_path類似,但更清楚路徑上的拉鍊。

手動更改__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... 
+1

我有一種感覺,它與命名空間包有關,但我在拼湊它的工作方式時遇到了問題。謝謝! – 2010-04-27 20:36:03

28

如果更改__path__,您可以強制解釋在不同的目錄去尋找屬於那個包的模塊。

這將允許你,例如,加載不同版本的基礎上運行時條件相同的模塊。如果你想在不同平臺上使用相同功能的不同實現,你可能會這樣做。

+0

Django使用這個在啓動時動態地加載django-admin.py命令! '命令=​​ {名稱:'django.core'在find_commands(__ path __ [0])中的名稱}} – 2014-05-10 18:46:23

7

除了選擇不同版本的基礎上運行時條件模塊的句法說,這個功能也可以讓您將包分解成多個部分/下載/同時保持單個邏輯封裝的外觀安裝。

請考慮以下情況。

  • 我有兩個包,mypkg_mypkg_foo
  • _mypkg_foo包含可選模塊mypkgfoo.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 

如果有人已經安裝的軟件包_mypkg_foo,則mypkg.foo是提供給他們。如果他們沒有,它不存在。

0

具體情況我遇到是當一個包:

您還可以使用__path__爲的monkeypatching,例如,我已經通過創建一個文件distutils/__init__.py,早期是sys.path monkeypatched在時間的distutils變得足夠大,我想將它的部分分割成子目錄,而不必更改任何引用它的代碼。

例如,我有一個名爲views的軟件包,它正在收集許多支持的實用程序函數,這些函數與包的主要頂級目的混淆。我能夠把這些配套功能移進子目錄utils並添加以下行__init__.pyviews包:

__path__.append(os.path.join(os.path.dirname(__file__), "utils")) 

隨着這一變化也views/__init_.py,我可以在新文件運行該軟件的其餘部分結構,而不需要對文件做進一步的修改。

(我試圖做的views/__init__.py文件import語句類似的東西,但子包模塊仍然不可見通過view包的進口 - 我不能完全肯定,如果我想的東西有;上歡迎評論)

(基於Python 2.7版安裝)這種反應