class 从非类型的对象继承是什么意思?

What does it mean for a class to inherit from an object which is not a type?

我在 Python 3.8 中遇到了 class 继承的奇怪案例。

我可以通过从本身不是 type 的实例继承来创建 class。在这种情况下,我预计会出现 TypeError,但事实并非如此。

class B:
    def __new__(cls, *args, **kwargs):
        print(args, kwargs)
        return super().__new__(cls)

b = B()  # prints: () {}

class A(b):  # I expected a TypeError here
    x = "foo"
# prints: ('A', (<__main__.B object at 0x7f32bd102390>,),
#         {'__module__': '__main__', '__qualname__': 'A', 'x': 'foo'}) {}

print(A)  # <__main__.B object at 0x7f20556c93d0>
print(isinstance(A, B))  # True
print(isinstance(A, type))  # False

看起来当我给 B() 作为 A 的基础时,然后 B 被用作元 class。

我的理解对吗?为什么会这样?而且我似乎找不到关于此行为的任何信息,它是否已记录或是否是特定于 cPython?

的实现怪癖

基本上,类型构造函数将检查基数以猜测最派生的元class。然后它将看到 A 的实例,并使用它的 class 作为“最派生的元 class”。所以,是的,“基础”中的 class 被用作元 class。

从那时起,它将调用检索到的“元class”来构建 B class 本身。因为它是一个 class,它被调用,这会像往常一样触发 class' __new__。由于它 return 是“A”的一个实例,即您作为“B”得到的实例:Python 不会妨碍验证元 class 是否可调用 returned 本身就是一个“class”——它可以是任何对象。这使人们可以灵活地滥用 class 语句来构建其他类型的对象,给定适当的 super-classes 或 metaclasses。在这种情况下,它恰好没有引发 TypeError 并且 return 你是“A”的一个实例。 (但你必须调整 class' __new__ 以避免 TypeError)


In [16]: class A: 
    ...:     def __new__(cls, *args, **kw): 
    ...:         print(args, kw) 
    ...:         return  super().__new__(cls) 
    ...:          
    ...:                

In [17]: class B(A()): pass                     
() {}
('B', (<__main__.A object at 0x7f26862395b0>,), {'__module__': '__main__', '__qualname__': 'B'}) {}

In [18]: type(B)        
Out[18]: __main__.A

In [19]: isinstance(B, A)                       
Out[19]: True