python 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__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
<class '__main__.Base'>, <class 'object'>)
>>>

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

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

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

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Python中super()函数简介及用法分享

    首先看一下super()函数的定义: super([type [,object-or-type]]) Return a **proxy object** that delegates method calls to a **parent or sibling** class of type. 返回一个代理对象, 这个对象负责将方法调用分配给第一个参数的一个父类或者同辈的类去完成. parent or sibling class 如何确定? 第一个参数的__mro__属性决定了搜索的顺序, sup

  • Python中super函数用法实例分析

    本文实例讲述了Python中super函数用法.分享给大家供大家参考,具体如下: 这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简单说, super函数是调用下一个父类(超类)并返回该父类实例的方法. 这里的下一个的概念参考后面的MRO表介绍. help介绍如下: super(type, obj) -> bound super object; requires isinstance(obj, type) super(type)

  • 深入解析Python编程中super关键字的用法

    官方文档中关于super的定义说的不是很多,大致意思是返回一个代理对象让你能够调用一些继承过来的方法,查找的机制遵循mro规则,最常用的情况如下面这个例子所示: class C(B): def method(self, arg): super(C, self).method(arg) 子类C重写了父类B中同名方法method,在重写的实现中通过super实例化的代理对象调用父类的同名方法. super类的初始方法签名如下: def __init__(self, type1, type2=None

  • Python编程中对super函数的正确理解和用法解析

    当在子类需要调用父类的方法时,在python2.2之前,直接用类名调用类的方法,即非绑定的类方法,并把自身对象self作参数传进去. class A(object): def say(self): print 'I am A' class B(A): def say(self): print 'I am B' A.say(self) b = B() b.say() 输出 I am B I am A 这样运作挺好,不过有个问题,当父类改了名字时,就要把这些显式调用父类的一个个更正,子类和父类耦合比

  • Python中的super用法详解

    一.问题的发现与提出 在Python类的方法(method)中,要调用父类的某个方法,在Python 2.2以前,通常的写法如代码段1: 代码段1: 复制代码 代码如下: class A:   def __init__(self):    print "enter A"    print "leave A" class B(A):   def __init__(self):    print "enter B"    A.__init__(sel

  • Python中super的用法实例

    super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复调用(钻石继承)等种种问题.总之前人留下的经验就是:保持一致性.要不全部用类名调用父类,要不就全部用 super,不要一半一半. 普通继承 复制代码 代码如下: class FooParent(object):      def __init__(self):          self.parent = 'I\'m the parent.'         

  • Python中super函数的用法

    描述 super() 函数用于调用下一个父类(超类)并返回该父类实例的方法. super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复调用(钻石继承)等种种问题. MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表. 语法 以下是 super() 方法的语法: super(type[, object-or-type]) 参数 type -- 类. object-or-type -- 类,一般是 se

  • python super的使用方法及实例详解

    功能 super功能:super函数是子类用于调用父类(超类)的一个方法. 用法 1.在子类 __init__() 方法中正确的初始化父类,保证相同的基类只初始化一次. 2.覆盖特殊方法. 3.解决多重继承中,子类重复调用父类方法的问题. 注意 super()继承只能用于新式类,用于经典类时就会报错. 新式类:必须有继承的类,如果无继承的,则继承object 经典类:没有父类,如果此时调用super就会出现错误:『super() argument 1 must be type, not clas

  • Python设计模式之工厂方法模式实例详解

    本文实例讲述了Python设计模式之工厂方法模式.分享给大家供大家参考,具体如下: 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延时到其子类. #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'Andy' """ 大话设计模式 设计模式--工厂方法模式 工厂方法模式(Factory Method Pattern):

  • Python多重继承之菱形继承的实例详解

    继承是面向对象编程的一个重要的方式,通过继承,子类就可以扩展父类的功能.在python中一个类能继承自不止一个父类,这叫做python的多重继承(Multiple Inheritance ). 语法 class SubclassName(BaseClass1, BaseClass2, BaseClass3, ...): pass 菱形继承 在多层继承和多继承同时使用的情况下,就会出现复杂的继承关系,多重多继承. 其中,就会出现菱形继承.如下图所示.mark 在这种结构中,在调用顺序上就出现了疑惑

  • Python使用struct处理二进制的实例详解

    Python使用struct处理二进制的实例详解 有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体. struct模块中最重要的三个函数是pack(), unpack(), calcsize() pack(fmt, v1, v2, ...)     按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流) unpack(fmt, string)   

  • python 中split 和 strip的实例详解

     python 中split 和 strip的实例详解 一直以来都分不清楚strip和split的功能,实际上strip是删除的意思:而split则是分割的意思. python中strip() 函数和 split() 函数的理解,有需要的朋友可以参考下. splite 和strip 都是Python 对字符串的处理. splite 意为分割,划分. a='123456' a.split('3') 输出为 ['12', '456'] 可以看到,使用何种字符切割,该字符也被略去.例如这里的字符"3&

  • Python入门之三角函数sin()函数实例详解

    描述 sin()返回的x弧度的正弦值. 语法 以下是sin()方法的语法: importmath math.sin(x) 注意:sin()是不能直接访问的,需要导入math模块,然后通过math静态对象调用该方法. 参数 x--一个数值. 返回值 返回的x弧度的正弦值,数值在-1到1之间. 实例 以下展示了使用sin()方法的实例: #!/usr/bin/python import math print "sin(3) : ", math.sin(3) print "sin(

  • Python入门之三角函数tan()函数实例详解

    描述 tan() 返回x弧度的正弦值. 语法 以下是 tan() 方法的语法: import math math.tan(x) 注意:tan()是不能直接访问的,需要导入 math 模块,然后通过 math 静态对象调用该方法. 参数 x -- 一个数值. 返回值 返回x弧度的正弦值,数值在 -1 到 1 之间. 实例 以下展示了使用 tan() 方法的实例: #!/usr/bin/python import math print "tan(3) : ", math.tan(3) pr

  • 对python 读取线的shp文件实例详解

    如下所示: import shapefile sf = shapefile.Reader("E:\\1.2\\cs\\DX_CSL.shp") shapes = sf.shapes() print shapes[1].parts print len(shapes) #79条记录 #print len(list(sf.iterShapes())) #79条记录 #for name in dir(shapes[3]): #不带参数时,返回当前范围内的变量.方法和定义的类型列表:带参数时,返

  • 对Python多线程读写文件加锁的实例详解

    Python的多线程在io方面比单线程还是有优势,但是在多线程开发时,少不了对文件的读写操作.在管理多个线程对同一文件的读写操作时,就少不了文件锁了. 使用fcntl 在linux下,python的标准库有现成的文件锁,来自于fcntl模块.这个模块提供了unix系统fcntl()和ioctl()的接口. 对于文件锁的操作,主要需要使用 fcntl.flock(fd, operation)这个函数. 其中,参数 fd 表示文件描述符:参数 operation 指定要进行的锁操作,该参数的取值有如

  • python中的二维列表实例详解

    1. 使用输入值初始化列表 nums = [] rows = eval(input("请输入行数:")) columns = eval(input("请输入列数:")) for row in range(rows): nums.append([]) for column in range(columns): num = eval(input("请输入数字:")) nums[row].append(num) print(nums) 输出结果为: 请

随机推荐