![](/img/trans.png)
[英]python 2.7 isinstance fails at dynamically imported module class
[英]isinstance fails for a type imported via package and from the same module directly
/Project
|-- main.py
|--/lib
| |--__init__.py
| |--foo.py
| |--Types.py
/Project/lib
已添加到PYTHONPATH
變量中。
類型.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)
現在的問題是, a
是lib.foo.Custom
類型,而 isinstance 調用將檢查它是否等於foo.Custom
,這顯然返回 false。
如何避免這個問題,而不必更改庫(lib)中的任何內容?
您不應該同時將lib
設為包並將其添加到PYTHONPATH
。 這使得可以將其模塊作為lib.
導入lib.
並直接為失敗做好准備。
如你所見,
lib.Types.Custom != Types.Custom
Python 搜索導入路徑並解析它找到的適當條目。
lib.Types
,它會將lib
目錄作為包導入,然后將lib/Types.py
作為其中的子模塊lib.Types
在sys.modules
創建模塊對象lib
和lib.Types
。Types
,它Types.py
作為獨立模塊導入,在sys.modules
創建模塊對象Types
。 因此, Types
和lib.Types
最終成為兩個不同的模塊對象。 Python 不會檢查它們是否是同一個文件,以保持簡單並避免猜測你。
(這實際上在 Python 的導入系統文章中的Traps for the Unwary 中列為“雙重導入陷阱”。)
如果您從PYTHONPATH
刪除lib
,則lib/foo.py
的導入將需要成為相對導入:
from .Types import Custom
或絕對導入:
from lib.Types import Custom
當一個模塊在同一進程中通過兩個不同的路徑import Types
——就像這里在foo.py
import Types
和在foo.py
import lib.Types
main.py
,它實際上被導入了兩次,產生了兩個不同的模塊對象,每個對象都有自己獨特的函數和類實例(您可以使用id(obj_or_class)
自己檢查),有效地打破is
和isinstance
測試。
這里的解決方案是將Project
(而不是Project/lib
)添加到您的pythonpath(fwiw無論如何都應該這樣做 - pythonpath/sys.path 應該是包含包和模塊的目錄列表,而不是包目錄本身)和在任何地方使用from lib.Type import Custom
,因此您只有一個模塊實例。
# For generating a class UUID: uuidgen -n "<MODULE_UUID>" -N <Python class name> -s
# Example: uuidgen -n "dec9b2e9-07c0-4f59-af97-92f171e6fe33" -N Args -s
MODULE_UUID = "dec9b2e9-07c0-4f59-af97-92f171e6fe33"
def get_class_uuid(obj_or_cls):
if isinstance(obj_or_cls, type):
# it's a class
return getattr(obj_or_cls, "CLASS_UUID", None)
# it's an object
return getattr(obj_or_cls.__class__, "CLASS_UUID", None)
def same_type(obj, cls):
return get_class_uuid(obj) == get_class_uuid(cls)
class Foo:
CLASS_UUID = "340637d8-5cb7-53b1-975e-d3f30bb825cd"
@staticmethod
def check_type(obj, accept_none=True):
if obj is None:
return accept_none
return same_type(obj, Foo)
...
assert Foo.check_type(obj)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.