我试图使我的类作为另一个对象出现,以规避正在使用的程序包中的惰性类型检查。更具体地说,我试图使我的对象作为另一个对象的实例(在我的情况下为tuple
)出现,而实际上它甚至不是该对象的派生。
为了实现这一目标,我计划重写__isinstance__
方法,根据docs,该方法应该完全执行我想要的操作。但是,似乎我不知道该怎么做,因为我的尝试没有成功。
这是一个SSCCE,应该在所有情况下都使isinstance
返回False
。
class FalseInstance(type):
def __instancecheck__(self, instance):
return False
class Foo(metaclass=FalseInstance):
pass
g = Foo()
isinstance(g, Foo)
> True
我在做什么错了?
答案 0 :(得分:5)
如果您在FalseInstance.__instancecheck__
内添加打印,您会发现它甚至没有被调用。但是,如果您调用isinstance('str', Foo)
,则会看到FalseInstance.__instancecheck__
确实被调用了。
这是由于对isinstance
的实现进行了优化,如果True
可以立即返回type(obj) == given_class
:
int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{
_Py_IDENTIFIER(__instancecheck__);
PyObject *checker;
/* Quick test for an exact match */
if (Py_TYPE(inst) == (PyTypeObject *)cls)
return 1;
.
.
.
}
答案 1 :(得分:2)
除了__metaclass__
的问题和精确类型匹配的快速路径之外,__instancecheck__
的工作方向与您尝试执行的相反。一个类的__instancecheck__
检查是否将其他对象视为该类的虚拟实例,而不是将该类的实例是否视为其他类的虚拟实例。
如果您希望对象在isinstance
检查中位于其类型附近(您实际上不应该这样做),那么实现该方法的方法是在__class__
附近,而不是实现{{1} }。
__instancecheck__
偶然地,如果要获取对象的实际类型,请使用class BadIdea(object):
@property
def __class__(self):
return tuple
print(isinstance(BadIdea(), tuple)) # prints True
而不是检查type
或__class__
。