python super用法

系统 1488 0

 

 

 

super()用法

功能

            super功能:super函数是子类用于调用父类(超类)的一个方法。
          

用法

            
              1
            
            
              .在子类 __init__() 方法中正确的初始化父类
            
            ,保证相同的基类只初始化一次。
            

2 .覆盖特殊方法。
            
              3
            
            .解决多重继承中,子类重复调用父类方法的问题。
          

注意

            
              super()继承只能用于新式类,用于经典类时就会报错。
新式类:必须有继承的类,如果无继承的,则继承object
经典类:没有父类,如果此时调用super就会出现错误:『super() argument 
            
            
              1
            
             must be type, not classobj)
          

 

 

在子类__init__()方法中正确初始化父类,保证相同的基类只初始化一次

            
              #
            
            
               假如说在父类中实现了一个方法,你想在子类中使用父类的这个方法并且做一定扩展但是又不想完全重写,并且这个场景中的继承属于多继承,那么super()就出场了,可以实现方法的增量修改。
            
            
              
#
            
            
               A(父类)有x属性,B(子类)想添加y属性:
            
          
            
              class
            
            
               A(object):
    
            
            
              def
            
            
              __init__
            
            
              (self,x):
        self.x 
            
            =
            
               x


            
            
              class
            
            
               B(A):
    
            
            
              def
            
            
              __init__
            
            
              (self,x,y):
        super(B,self,).
            
            
              __init__
            
            
              (x)
        self.y 
            
            =
            
               y

a  
            
            = A(2
            
              )
b  
            
            = B(2,4
            
              )

            
            
              print
            
            
              (a.x)

            
            
              print
            
            (b.x,b.y)
          

 

 

覆盖Python特殊方法

            
              class
            
            
               Proxy:
    
            
            
              def
            
            
              __init__
            
            
              (self, obj):
        self._obj 
            
            =
            
               obj

    
            
            
              #
            
            
               Delegate attribute lookup to internal obj
            
            
              def
            
            
              __getattr__
            
            
              (self, name):
        
            
            
              return
            
            
               getattr(self._obj, name)

    
            
            
              #
            
            
               Delegate attribute assignment
            
            
              def
            
            
              __setattr__
            
            
              (self, name, value):
        
            
            
              if
            
             name.startswith(
            
              '
            
            
              _
            
            
              '
            
            
              ):
            super().
            
            
              __setattr__
            
            (name, value) 
            
              #
            
            
               Call original __setattr__
            
            
              else
            
            
              :
            setattr(self._obj, name, value)
            
          
            
              #
            
            
               在上面代码中,__setattr__() 的实现包含一个名字检查。 如果某个属性名以下划线(_)开头,就通过 super() 调用原始的 __setattr__() , 否则的话就委派给内部的代理对象 self._obj 去处理。 这看上去有点意思,因为就算没有显式的指明某个类的父类, super() 仍然可以有效的工作。
            
          

 

 

解决多重继承中,子类重复调用父类方法的问题

              
                class
              
              
                 Base:
    
              
              
                def
              
              
                __init__
              
              
                (self):
        
              
              
                print
              
              (
              
                '
              
              
                Base.__init__
              
              
                '
              
              
                )


              
              
                class
              
              
                 A(Base):
    
              
              
                def
              
              
                __init__
              
              
                (self):
        Base.
              
              
                __init__
              
              
                (self)
        
              
              
                print
              
              (
              
                '
              
              
                A.__init__
              
              
                '
              
              )
            

尽管对于大部分代码而言这么做没什么问题,但是在更复杂的涉及到多继承的代码中就有可能导致很奇怪的问题发生。 比如,考虑如下的情况:

                
                  class
                
                
                   Base:
    
                
                
                  def
                
                
                  __init__
                
                
                  (self):
        
                
                
                  print
                
                (
                
                  '
                
                
                  Base.__init__
                
                
                  '
                
                
                  )


                
                
                  class
                
                
                   A(Base):
    
                
                
                  def
                
                
                  __init__
                
                
                  (self):
        Base.
                
                
                  __init__
                
                
                  (self)
        
                
                
                  print
                
                (
                
                  '
                
                
                  A.__init__
                
                
                  '
                
                
                  )


                
                
                  class
                
                
                   B(Base):
    
                
                
                  def
                
                
                  __init__
                
                
                  (self):
        Base.
                
                
                  __init__
                
                
                  (self)
        
                
                
                  print
                
                (
                
                  '
                
                
                  B.__init__
                
                
                  '
                
                
                  )


                
                
                  class
                
                
                   C(A,B):
    
                
                
                  def
                
                
                  __init__
                
                
                  (self):
        A.
                
                
                  __init__
                
                
                  (self)
        B.
                
                
                  __init__
                
                
                  (self)
        
                
                
                  print
                
                (
                
                  '
                
                
                  C.__init__
                
                
                  '
                
                )
              

如果你运行这段代码就会发现  Base.__init__()  被调用两次,如下所示:

              
                >>> 
                
                  c 
                  
                    = 
                    
                      C
                      
                        ()

                        
                          Base.__init__ 
                          
                            A.__init__ 
                            
                              Base.__init__ 
                              
                                B.__init__ 
                                
                                  C.__init__ 
                                  
                                    >>> 
                                  
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            

可能两次调用  Base.__init__()  没什么坏处,但有时候却不是。 另一方面,假设你在代码中换成使用  super()  ,结果就很完美了:

                
                  class
                
                
                   Base:
    
                
                
                  def
                
                
                  __init__
                
                
                  (self):
        
                
                
                  print
                
                (
                
                  '
                
                
                  Base.__init__
                
                
                  '
                
                
                  )


                
                
                  class
                
                
                   A(Base):
    
                
                
                  def
                
                
                  __init__
                
                
                  (self):
        super().
                
                
                  __init__
                
                
                  ()
        
                
                
                  print
                
                (
                
                  '
                
                
                  A.__init__
                
                
                  '
                
                
                  )


                
                
                  class
                
                
                   B(Base):
    
                
                
                  def
                
                
                  __init__
                
                
                  (self):
        super().
                
                
                  __init__
                
                
                  ()
        
                
                
                  print
                
                (
                
                  '
                
                
                  B.__init__
                
                
                  '
                
                
                  )


                
                
                  class
                
                
                   C(A,B):
    
                
                
                  def
                
                
                  __init__
                
                
                  (self):
        super().
                
                
                  __init__
                
                ()  
                
                  #
                
                
                   Only one call to super() here
                
                
                  print
                
                (
                
                  '
                
                
                  C.__init__
                
                
                  '
                
                )
              

运行这个新版本后,你会发现每个  __init__()  方法只会被调用一次了:

              
                >>> 
                
                  c 
                  
                    = 
                    
                      C
                      
                        ()

                        
                          Base.__init__ 
                          
                            B.__init__ 
                            
                              A.__init__ 
                              
                                C.__init__ 
                                
                                  >>>
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            

为了弄清它的原理,我们需要花点时间解释下Python是如何实现继承的。 对于你定义的每一个类,Python会计算出一个所谓的方法解析顺序(MRO)列表。 这个MRO列表就是一个简单的所有基类的线性顺序表。例如:

              
                >>> 
                
                  C
                  
                    .
                    
                      __mro__

                      
                        (
                        
                          , 
                          
                            , 
                            
                              ,

                              
                                
                                  , 
                                  
                                    ) 
                                    
                                      >>> 
                                    
                                  
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            

为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

而这个MRO列表的构造是通过一个C3线性化算法来实现的。 我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

  • 子类会先于父类被检查
  • 多个父类会根据它们在列表中的顺序被检查
  • 如果对下一个类存在两个合法的选择,选择第一个父类

老实说,你所要知道的就是MRO列表中的类顺序会让你定义的任意类层级关系变得有意义。

当你使用  super()  函数时,Python会在MRO列表上继续搜索下一个类。 只要每个重定义的方法统一使用  super()  并只调用它一次, 那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次。 这也是为什么在第二个例子中你不会调用两次  Base.__init__()  的原因。

 

参考:https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p07_calling_method_on_parent_class.html


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论