Python 类从非类型的对象继承意味着什么?
我在Python3.8中遇到了一个奇怪的类继承案例 我可以通过从本身不是Python 类从非类型的对象继承意味着什么?,python,python-3.x,class,inheritance,metaclass,Python,Python 3.x,Class,Inheritance,Metaclass,我在Python3.8中遇到了一个奇怪的类继承案例 我可以通过从本身不是类型的实例继承来创建类。我希望在这种情况下会出现TypeError,但事实并非如此 class B: def __new__(cls, *args, **kwargs): print(args, kwargs) return super().__new__(cls) b = B() # prints: () {} class A(b): # I expected a TypeE
类型的实例继承来创建类。我希望在这种情况下会出现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类:
定义(cls,*ARG,**kwargs):
打印(args、kwargs)
返回super()
b=b()#打印:(){}
A类(b):#我以为这里会有打字错误
x=“foo”
#印刷品:(‘A’,(,),
#{{}模块{}}}}}}}}}}}}}}}}}
印刷版(一)
打印(实例(A,B))#正确
打印(isinstance(A,类型))#错误
看起来,当我将B()
作为A
的基础时,B
被用作元类
我的理解正确吗?为什么会这样?我似乎找不到关于这种行为的任何信息,它是有文档记录的还是特定于cPython的一种实现怪癖?基本上,类型构造函数会检查基础以猜测最派生的元类。然后,它将看到A
的实例,并将其类用作“最派生的元类”。所以,是的,“基”中的类被用作元类
从那时起,它将调用检索到的“元类”来构建B类本身。因为它是一个类,所以它被调用,这会像往常一样触发类“\uuuu new\uuuu
”。因为它返回一个“A”的实例,这就是作为“B”得到的实例:Python不会妨碍验证返回的元类本身是否是“类”,它可以是任何对象。这使我们能够灵活地滥用class语句来构建其他类型的对象,并提供适当的超类或元类。在本例中,它只是碰巧没有引发TypeError并返回一个“a”的实例。(但是您必须调整类'\uuuuu new\uuuu
,以避免类型错误)
在[16]中:A类:
…:def_uuunew_uuuu(cls,*args,**kw):
…:打印(args,kw)
…:return super()。\uuuu new\uuuu(cls)
...:
...:
在[17]中:B类(A()):通过
() {}
('B',(,),{'U_________'模块:''U_____'main','U____'qualname:'B'}){}
In[18]:类型(B)
Out[18]:uu main_uuu.A
在[19]中:isinstance(B,A)
Out[19]:对
似乎在代码段末尾调用A()
会引发TypeError:“B”对象不可调用
@JakeLevi是的,这是因为A最终是B的实例,而不是类型。。。由于某些语义原因,我看不到。另外,如果我注释掉您对B
的定义,并将其替换为class B:pass
,那么class A(B):
行将引发TypeError:B()不带参数,正如您所期望的那样。因此,我猜您的问题的答案与\uuuuu new\uuuuuu
特殊方法的行为有关,您可以在这里了解更多:谢谢。这里的关键字实际上是“派生元类”。从那里我可以找到我需要的所有文档。
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