__instancecheck__ - 覆盖显示无效 - 我做错了什么?

__instancecheck__ - overwrite shows no effect - what am I doing wrong?

我试图让我的 class 显示为一个不同的对象,以规避我正在使用的包中的延迟类型检查。更具体地说,我试图让我的对象显示为另一个对象的实例(tuple 在我的例子中),而实际上它甚至不是那个对象的派生。

为了实现这一点,我计划覆盖 __isinstance__ 方法,根据 docs,该方法应该完全符合我的要求。但是,我似乎不明白该怎么做,因为我的尝试一直没有成功。

这是一个 SSCCE,应该 在所有情况下都isinstance return False 但是没有。

class FalseInstance(type):
    def __instancecheck__(self, instance):
        return False

class Foo(metaclass=FalseInstance):
    pass

g = Foo()
isinstance(g, Foo)
> True

我做错了什么?

如果您在 FalseInstance.__instancecheck__ 中添加打印,您会发现它甚至没有被调用。但是,如果您调用 isinstance('str', Foo),那么您会看到确实调用了 FalseInstance.__instancecheck__

这是由于 isinstance 实施中的优化,如果 type(obj) == given_class:

立即 returns True
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

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

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

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

print(isinstance(BadIdea(), tuple)) # prints True

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