Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 类从非类型的对象继承意味着什么?_Python_Python 3.x_Class_Inheritance_Metaclass - Fatal编程技术网

Python 类从非类型的对象继承意味着什么?

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

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