python super方法,Python super()使用注意事项

  python super方法,Python super()使用注意事项

  很高大上的函数,如果在python的manual 13里用多了,可以让你看起来像个高手23333。但其实还是很重要的。简单来说,超级函数就是调用下一个父类(超类)并返回父类实例的方法。这里的下一个概念是在后面的MRO表中介绍的。

  帮助介绍如下:

  超级(type,obj)绑定的超级对象;需要isinstance(obj,type)

  超级(类型)-未绑定的超级对象

  超(type,type2)绑定的超对象;需要issubclass(类型2,类型)

  调用协作超类方法的典型用法:

  丙类(乙类):

  定义方法(self,arg):

  超级(C,自我)。meth(arg)。因此,super有三种用法。第一个参数总是调用父类的类,第二个参数是可选的(返回未绑定的父类对象)。它也可以是该类的实例对象或子类。最终返回父类的所有实例(绑定或未绑定)。在Python3中,super函数的另一种用法是direct super(),相当于super(type,first parameter)。第一个参数是一般的传入self实例本身,因为它通常也用py2编写。

  另外,在py2中,super只支持新类(new-style class,继承自object)。

  为什么要调用父类?当一个类继承时,如果一个方法被重定义,它将覆盖与父类同名的相应方法。通过调用父类的实例,父类的功能可以同时在子类中实现。例如:

  #应该是基于python2中对象的新类。

  A类(对象):

  def __init__(self):

  打印“输入A”

  打印“留下一个”

  B(A)类:

  def __init__(self):

  打印输入B

  超级(B,自我)。__init__()

  打印“离开B”

  b=B()

  输入B

  输入A

  留下一个

  Leave B可以通过调用super实现父类实例的初始化功能。这是实践中经常用到的(因为需要继承父类的功能,又有新的功能)。

  使用父类直接调用的区别其实上面的超函数方法也可以这样写:

  A类(对象):

  def __init__(self):

  打印“输入A”

  打印“留下一个”

  B(A)类:

  def __init__(self):

  打印输入B

  A.__init__(self)

  Print leave B 直接用父类名调用父类其实是可行的。至少在上面的例子中,现在效果是一样的。这个方法也是调用老类中父类的唯一方法(老类没有super)。

  通过父类名调用方法是非常常见和直观的。但是,它的效果和超级不一样。例如:

  A类(对象):

  def __init__(self):

  打印“输入A”

  打印“留下一个”

  B(A)类:

  def __init__(self):

  打印输入B

  A.__init__(self)

  打印“离开B”

  丙类(甲类):

  def __init__(self):

  打印输入C

  A.__init__(self)

  打印“左C”

  D类(B、C类):

  def __init__(self):

  打印输入D

  B.__init__(self)

  C.__init__(self)

  打印“离开D”

  d=D()

  输入D

  输入B

  输入A

  留下一个

  离开B

  输入C

  输入A

  留下一个

  离开C

  离开D可以发现A的初始化函数被执行了两次。因为要同时实现B和C的初始化函数,所以分别调用两次是必然的结果。

  但是如果改写成super呢?

  A类(对象):

  def __init__(self):

  打印“输入A”

  打印“留下一个”

  B(A)类:

  def __init__(self):

  打印输入B

  超级(B,自我)。__init__()

  打印“离开B”

  丙类(甲类):

  def __init__(self):

  打印输入C

  超级(C,自我)。__init__()

  打印“左C”

  D类(B、C类):

  def __init__(self):

  打印输入D

  超级(D,自我)。__init__()

  打印“离开D”

  d=D()

  输入D

  输入B

  输入C

  输入A

  留下一个

  离开C

  离开B

  离开D会发现所有的父类ABC都只执行一次,而不是像以前一样初始化A两次。

  然后,一个奇怪的事情被发现了:父类的执行是BCA的命令,而且都是输入然后统一的。这就是MRO表问题,后面会讨论。

  如果没有多重继承,super其实类似于通过父类调用方法。但是,super还有一个好处:当B继承A,写成A.__init__,如果根据需要把所有的重构都改成继承E,那么都得重新改一遍!这很麻烦,容易出错!但是使用super()不需要一个一个改(在类定义里改就行了)。反正你可以发现超级没那么简单。

  MRO餐桌上的MRO是什么?可以通过以下方式转出:

  D.mro() #或d.__class__。mro()或D.__class__。mro(D)

  [D,B,C,A,object]

  磁共振成像技术

  [B,A,对象]

  帮助(维修)

  #文档字符串:

  #mro() -列表

  #返回类型的方法解析顺序

  #Type: method_descriptorMRO是一个类的方法解析序列表,实际上是继承父类方法时的序列表(类继承序列表来理解它)。

  这块表有什么用?首先,找出真正的管理员做了什么:

  高级定义(cls,inst):

  mro=inst。__class__。mro()

  Return mro[mro.index(cls) 1]换句话说,super方法实际上调用了cls的mro表中的下一个类。如果是简单的一行单继承,那就是父类——父类一个一个往下。但是对于多重继承,应该遵循MRO表中的顺序。以上面D的调用为例:

  数据的初始化

  -D(回车D) super(D,self)

  -父类B(输入B)超级(B,自身)

  -父类C (Enter C)超级(C,self)

  -Parent父类A(输入A)(退出A) #如果是,继续超(A,self)-object(停止)

  -(出口C)

  -(B出口)

  -(退出D)所以,MRO表中的超类初始化函数只执行一次!

  那么,MRO的秩序是什么?这可以参考官方指令Python 2.3方法解析顺序。基本上就是计算每个类的MRO(从父类到子类的顺序),合并成一条线。请遵循以下规则:

  在MRO中,基类总是出现在派生类之后。如果有多个基类,基类的相对顺序保持不变。这个原则包括两点:

  当类被定义影响相对顺序时,基类的继承顺序总是在派生类之后。

  那么MRO就是:F-E-B-C-D-A-Object

  怎么解释呢?

  按照官方的方法,是:

  L(O)=O

  L(B)=B O

  L(A)=A O

  L(C)=C A O

  L(D)=D A O

  L(E)=E merge(L(B),L(C))

  =E合并(BO,CAO)

  =E B merge(O,CAO)

  =E B C merge(O,AO)

  =E B C A merge(O,O)

  =欧洲银行

  L(F)=F merge(L(E),L(D))

  =F合并(EBCAO,DAO)

  =F EBC合并(AO,DAO)

  =F EBC D合并(AO,AO)

  =F EBC D AO看起来很复杂.但在MRO仍然如此。基类总是出现在派生类之后。如果有多个基类,基类的相对顺序保持不变。所以,就我个人而言,我认为我可以这样想:

  首先找到最长最深的继承路径F- E- C- A- object。(因为基类总是出现在派生类之后是必然的。)相似深度先设置休止符顺序:F- E- B- obj

  ,F- D- A-object如果有多个基类,基类的相对顺序会保持不变,类似于合并时提前的项。所以安排这些路线:(FEBO,FECAO,FDAO)F- E- B- obj

  而E(B,C)决定B在C之前,所以F- E- B- C- A- obj

  (相当于F合并(EBO,ECAO)

  ).一个物体

  而F(E,D)确定D在E之后,所以D在E之后a之前,因为相对顺序,所以等价于FE归并(BCAO,道)

  ,所以FE BC D AO

  这是一个超级课堂。当我们调用super()时,我们实际上实例化了一个超类。你没看错。super是一个类,既不是关键字,也不是函数等其他数据结构:

  A类:通过

  .

  s=超级(A)

  类型

  在大多数情况下,super包含两条非常重要的信息:一个MRO和一个MRO的类。如下调用super时:

  Super(a_type,obj)MRO指的是(obj)类型的MRO,MRO的那个类是a_type,而is instance(obj,A _ type)==true。

  这样称呼的时候:

  Super(type1,type2)MRO指的是type2的MRO,MRO的类是type1,issubclass(type2,type1)==True。

  那么,super()实际上做了什么呢?简单来说:在MRO中提供一个MRO和一个类C,super()会返回一个对象,从MRO中C之后的类中查找方法。

  也就是说,查找方式时不是像常规方法一样从所有的大修类中查找,而是从大修的尾巴中查找。

  举个栗子,有个MRO:

  [甲、乙、丙、丁、戊、对象]下面的调用:

  超级(丙,甲)款.foo()超级只会从C之后查找,即:只会在D或E或目标中查找富(中国姓氏)方法。

  多继承中极好的的工作方式再回到前面的

  d=D()

  d.add(2)

  打印(数据)现在你可能已经有点眉目,为什么输出会是

  自我是__main__ .位于0x10ce10e48 @D.add的d对象

  自我是__main__ .位于0x10ce10e48 @B的d对象。添加

  自我是__main__ .位于0x10ce10e48 @C.add的d对象

  自我是__main__ .位于0x10ce10e48 @A.add的d对象

  19下面我们来具体分析一下:

  D的大修是:[D,B,C,A,object]。备注:可以通过D.mro() (Python 2使用D.__mro__)来查看D的大修信息)详细的代码分析如下:A类:

  def __init__(self):

  self.n=2

  定义添加(自身,m):

  # 第四步

  # 来自d。添加中的极好的

  # self==d,self.n==d.n==5

  print(self is {0} @A.add .格式(自身))

  self.n=m

  # d.n==7

  乙(甲)类:

  def __init__(self):

  self.n=3

  定义添加(自身,m):

  # 第二步

  # 来自d。添加中的极好的

  # self==d,self.n==d.n==5

  打印(自己是{0} @B.add .格式(自身))

  # 等价于suepr(B,self).添加(m)

  #自我的大修是[D,B,C,A,object]

  # 从B之后的【丙、甲、对象]中查找增加方法

  超级()。添加(m)

  # 第六步

  #数据=11

  self.n=3

  # d.n=14

  丙类(甲类):

  def __init__(self):

  self.n=4

  定义添加(自身,m):

  # 第三步

  # 来自乙。添加中的极好的

  # self==d,self.n==d.n==5

  print(self is {0} @C.add .格式(自身))

  # 等价于suepr(C,self).添加(m)

  #自我的大修是[D,B,C,A,object]

  # 从C之后的【答,对象]中查找增加方法

  超级()。添加(m)

  # 第五步

  # d.n=7

  self.n=4

  #数据=11

  D类(B、C类):

  def __init__(self):

  self.n=5

  定义添加(自身,m):

  # 第一步

  print(self is {0} @D.add .格式(自身))

  # 等价于超级(四、自我)。添加(m)

  #自我的大修是[D,B,C,A,object]

  # 从D之后的[乙,丙,甲,对象]中查找增加方法

  超级()。添加(m)

  # 第七步

  # d.n=14

  self.n=5

  # self.n=19

  d=D()

  d.add(2)

  打印(数据)调用过程图如下:

  D.mro()==[D,B,C,A,object]

  d=D()

  d.n==5

  d.add(2)

  D类(乙、丙):乙类(甲):丙类答:答类:

  def add(self,m): def add(self,m): def add(self,m): def add(self,m):

  超级()。添加(m) 1 .-超级()。添加(m) 2 .-超级()。添加(m) 3 .- self.n=m

  self.n=5 - 6 .self.n=3 - 5 .self.n=4 - 4 .-

  (14 5=19) (11 3=14) (7 4=11) (5 2=7)

  现在你知道为什么d.add(2)后域名的值是19 了吧;)

  参考参考1

  参考2

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: