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
我在 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