__instancecheck__-覆盖不起作用-我在做什么错?

时间:2018-09-04 14:50:44

标签: python python-3.x metaclass magic-methods isinstance

我试图使我的类作为另一个对象出现,以规避正在使用的程序包中的惰性类型检查。更具体地说,我试图使我的对象作为另一个对象的实例(在我的情况下为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

我在做什么错了?

2 个答案:

答案 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;
    .
    .
    .
}

From Python's source code

答案 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__