簡體   English   中英

從我的 Python 模塊導入另一個模塊

[英]Making another module importable from my Python module

我有一個像這樣的 Python 模塊目錄結構:

my_module
|--__init__.py
|--public_interface
|  |--__init__.py
|  |--my_sub_module
|  |  |--__init__.py
|  |  |--code.py
|  |--some_more_code.py
|--other directories omitted

現在, public_interface目錄(以及其他幾個目錄)僅用於將代碼組織成邏輯子單元,作為我和其他開發人員的指南。 my_module的最終用戶只能將其視為my_module.my_sub_module ,中間沒有public_interface

我寫了這些__init__.py文件:

my_module.__init__.py

 from .public_interface import *

my_module.public_interface.__init__.py

 from . import my_sub_module from .some_more_code import *

my_module.public_interface.my_sub_module.__init__.py

 from .code import *

只要用戶只導入頂級模塊,這就能正常工作:

import my_module

my_module.my_sub_module.whatever  # Works as intended

但是,這不起作用:

from my_module import my_sub_module

也不:

import my_module.my_sub_module

我必須改變什么才能使這最后兩個進口工作?

導入系統只允許將實際的包和模塊作為帶點的模塊名稱的一部分直接導入,但是您的:

from .public_interface import *

hack 只是使my_sub_module成為my_module包的一個屬性,而不是用於導入系統的實際子模塊。 它因為同樣的原因而中斷:

from collections._sys import *

休息; 是的,作為一個實現細節, collections包碰巧導入別名為_sys sys ,但這實際上並沒有使_sys成為collections的子包,它只是collections包上的許多屬性之一。 從導入機制的角度來看, my_sub_modulemy_module的子模塊,而_syscollections的子模塊; 嵌套在my_module下的子目錄中這一事實無關緊要。

也就是說,導入系統提供了一個鈎子,允許您將其他任意目錄視為包的一部分,__path__屬性 默認情況下, __path__只包含包本身的路徑(因此my_module__path__默認為['/absolute/path/to/my_module'] ),但您可以根據需要以編程方式對其進行操作; 解析子模塊時,它只會搜索__path__的最終內容,就像導入頂級模塊搜索sys.path 因此,要解決您的特定情況(希望public_interface所有包/模塊都可以導入,而無需在導入行中指定public_interface ),只需將my_module/__init__.py文件更改為具有以下內容:

import os.path
__path__.append(os.path.join(os.path.dirname(__file__), 'public_interface'))

所做的只是告訴導入系統,當import mymodule.XXXX發生時( XXXX是真實姓名的占位符),如果它找不到my_module/XXXXmy_module/XXXX.py ,它應該尋找my_module/public_interface/XXXXmy_module/public_interface/XXXX.py 如果你想讓它先搜索public_interface ,把它改成:

__path__.insert(0, os.path.join(os.path.dirname(__file__), 'public_interface'))

或者讓它檢查public_interface (所以直接在my_module下沒有任何東西是可導入的),使用:

__path__[:] = [os.path.join(os.path.dirname(__file__), 'public_interface')]

完全替換__path__的內容。


旁注:您可能想知道為什么os.path是此規則的一個例外; 在 CPython 上, os是一個帶有屬性path的普通模塊(它恰好是模塊posixpathntpath取決於平台),但您可以執行import os.path 這是有效的,因為os模塊在被導入時,顯式(和hackily)填充了os.pathsys.modules緩存。 這是不正常的,它有性能成本; import os必須始終隱式地導入os.path ,即使從未使用過os.path中的任何內容。 __path__避免了這個問題; 除非要求,否則不會導入任何內容。

可以通過使my_module/__init__.py包含以下內容獲得相同的結果:

import sys
from .public_interface import my_sub_module

sys.modules['my_module.my_sub_module'] = my_sub_module

這將允許人們在只完成import my_module使用my_module.my_submodule ,但這將強制my_module任何import導入public_interfacemy_sub_module ,即使從未使用過my_sub_module中的任何內容。 由於歷史原因, os.path繼續這樣做(很久以前只使用os.path API 和import os ,並且很多代碼依賴於這種錯誤行為,因為程序員很懶惰並且它有效),但是新代碼不應該使用這個黑客。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM