2017-10-12 51 views
3
/Project 
|-- main.py 
|--/lib 
| |--__init__.py 
| |--foo.py 
| |--Types.py 

/Project/lib已被添加到PYTHONPATH變量。isinstance失敗用於經由包進口類型,並從相同的模塊直接

Types.py:

class Custom(object): 
    def __init__(self): 
     a = 1 
     b = 2 

foo.py:

from Types import Custom 
def foo(o): 
    assert isinstance(o, Custom) 

最後,從main.py

from lib.Types import Custom 
from lib.foo import foo 
a = Custom() 
foo(a) 

問題ñ ow是,a的類型是lib.foo.Custom,而isinstance調用將檢查它是否等於foo.Custom,這顯然返回false。

如何避免此問題,而不必更改庫(lib)中的任何內容?

+1

無論導入路徑如何,類引用都將保持不變。我不認爲你應該在這裏面對任何問題。 – hspandher

+2

您在'lib'目錄中缺少'__init __。py'。請參閱[這裏](https://stackoverflow.com/questions/46688216/in-python3-does-import-work-transitively/46688250#46688250) – uphill

+1

+'types'是存在於標準庫中的名稱,我' d去換一個。 – uphill

回答

6

您不應該同時製作lib包並將其添加到PYTHONPATH。這使得它可以直接導入模塊lib.並自行設置失敗。

正如你所看到的,

lib.Types.Custom != Types.Custom 
因爲 the way Python imports work

Python搜索導入路徑並解析它找到的相應條目。

  • 當您導入lib.Types,其進口lib目錄作爲一個包,然後lib/Types.py因爲它裏面的子模塊,創建模塊對象libsys.moduleslib.Types
  • 當您導入Types時,它將作爲獨立模塊導入Types.py,在sys.modules中創建模塊對象Types

因此,Typeslib.Types結束爲兩個不同的模塊對象。Python不檢查它們是否是相同的文件以保持簡單並避免再次猜測你。

(這在Traps for the Unwary in Python’s Import System文章「雙進口陷阱」實際上列出)。


如果從PYTHONPATH刪除lib,在lib/foo.py進口將需要成爲一個相對進口:

from .Types import Custom 

或絕對導入:

from lib.Types import Custom 
+1

個人而言,我不會稱之爲「陷阱」,因爲「陷阱」意味着一些與直覺相反的東西。通過兩條不同的路線在同一個地方訪問相同的東西是一件愚蠢的事情 - 不管在任何地方,而不僅僅是Python。所以,這對於糟糕的設計來說是一種應有的懲罰。這總是一件好事 - 它既教導bot客一個寶貴的教訓,並保存他們的用戶和同行代替他們的錯誤。 –

3

當一個模塊導入通兩種不同的路徑在同一個進程 - 在main.pyfoo.pyimport lib.Types喜歡這裏import Types,它是真正進口的兩倍,從而產生兩個不同的模塊對象,每個都有它自己獨特的功能和類實例(你可以自己用id(obj_or_class)查詢),有效打破isisinstance的測試。

該解決方案在這裏是添加Project(不Project/lib)到您的PYTHONPATH(FWIW這就是應該已經做反正 - PYTHONPATH/sys.path中應包含包和模塊,而不是包目錄列表目錄本身),並且在任何地方都使用from lib.Type import Custom,因此您只有一個模塊實例。