![](/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.