为什么不调用__instancecheck__?

drd*_*rez 5 python metaclass class python-3.x python-3.6

我有以下python3代码:

class BaseTypeClass(type):
    def __new__(cls, name, bases, namespace, **kwd):
        result = type.__new__(cls, name, bases, namespace)
        print("creating class '{}'".format(name))
        return result

    def __instancecheck__(self, other):
        print("doing instance check")
        print(self)
        print(other)
        return False


class A(metaclass=BaseTypeClass):
    pass

print(type(A))
print(isinstance(A(), A))
Run Code Online (Sandbox Code Playgroud)

当我运行它时,Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32我得到以下输出

creating class 'A'
<class '__main__.BaseTypeClass'>
True
Run Code Online (Sandbox Code Playgroud)

为什么不输出doing instance check?该文件说,__instancecheck__方法需要在元类,而不是类本身,这是我在这里做定义.我甚至验证了自creating class 'A'打印以来正在使用的元类.但是,当我调用isinstance它时似乎使用默认实现而不是我在元类中定义的实现.

我可能没有正确使用元类,但我无法弄清楚我犯了哪些错误.

Jim*_*ard 5

isinstance函数快速检查以查看作为参数提供的实例的类型是否与类的实例类型相同.如果是这样,它会提前返回并且不会调用您的自定义__instancecheck__.

这是一种优化,用于避免在__instancecheck__不需要时对(它的Pythonland代码)进行昂贵的调用.

您可以在CPython实现中查看特定的测试PyObject_IsInstance,即处理isinstance调用的函数:

/* Quick test for an exact match */
if (Py_TYPE(inst) == (PyTypeObject *)cls)
    return 1;
Run Code Online (Sandbox Code Playgroud)

当然,__instancecheck__当测试不是时,你的正确发射True:

>>> isinstance(2, A)
doing instance check
<class '__main__.A'>
2
False
Run Code Online (Sandbox Code Playgroud)

我不确定这是否是特定于实现的,但我想是这样的,因为在相应的PEP部分和文档中都没有提到这一点isinstance.


有趣的是:issubclass实际上并没有这样做.由于它的实现它总是调用__subclasscheck__.我已经在这一段时间内打开了一个问题,这个问题仍然悬而未决.