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

Nea*_*roo 1 python metaclass magic-methods isinstance python-3.x

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

我究竟做错了什么?

use*_*ica 7

除了__metaclass__精确类型匹配的问题和快速路径之外,它的__instancecheck__工作方向与您尝试做的相反。类__instancecheck__检查其他对象是否被视为该类的虚拟实例,而不是该类的实例是否被视为其他类的虚拟实例。

如果你希望你的对象在isinstance检查中谎报它们的类型(你真的不应该),那么这样做的方法是谎报__class__,而不是实现__instancecheck__

class BadIdea(object):
    @property
    def __class__(self):
        return tuple

print(isinstance(BadIdea(), tuple)) # prints True
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果您想获取对象的实际类型,请使用type而不是检查__class__isinstance


Dee*_*ace 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;
    .
    .
    .
}
Run Code Online (Sandbox Code Playgroud)

从Python的源代码

  • @Nearoo:`__instancecheck__`主要是为了使更多的`insinstance`检查通过,而不是更少。另外,没有`__isinstance__`。 (3认同)