python中的super用法详解_【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__(self)

print "leave B"

>>> b = B()

enter B

enter A

leave A

leave B

即,使用非绑定的类方法(用类名来引用的方法),并在参数列表中,引入待绑定的对象(self),从而达到调用父类的目的。

这样做的缺点是,当一个子类的父类发生变化时(如类B的父类由A变为C时),必须遍历整个类定义,把所有的通过非绑定的方法的类名全部替换过来,例如代码段2,

代码段2:

class B(C): # A --> C

def __init__(self):

print "enter B"

C.__init__(self) # A --> C

print "leave B"

如果代码简单,这样的改动或许还可以接受。但如果代码量庞大,这样的修改可能是灾难性的。

因此,自Python 2.2开始,Python添加了一个关键字super,来解决这个问题。下面是Python 2.3的官方文档说明:

super(type[, object-or-type])

Return the superclass of type. If the second argument is omitted the super object

returned is unbound. If the second argument is an object, isinstance(obj, type)

must be true. If the second argument is a type, issubclass(type2, type) must be

true. super() only works for new-style classes.

A typical use for calling a cooperative superclass method is:

class C(B):

def meth(self, arg):

super(C, self).meth(arg)

New in version 2.2.

从说明来看,可以把类B改写如代码段3:

代码段3:

class A(object): # A must be new-style class

def __init__(self):

print "enter A"

print "leave A"

class B(C): # A --> C

def __init__(self):

print "enter B"

super(B, self).__init__()

print "leave B"

尝试执行上面同样的代码,结果一致,但修改的代码只有一处,把代码的维护量降到最低,是一个不错的用法。因此在我们的开发过程中,super关键字被大量使用,而且一直表现良好。

在我们的印象中,对于super(B, self).__init__()是这样理解的:super(B, self)首先找到B的父类(就是类A),然后把类B的对象self转换为类A的对象(通过某种方式,一直没有考究是什么方式,惭愧),然后“被转换”的类A对象调用自己的__init__函数。考虑到super中只有指明子类的机制,因此,在多继承的类定义中,通常我们保留使用类似代码段1的方法。

有一天某同事设计了一个相对复杂的类体系结构(我们先不要管这个类体系设计得是否合理,仅把这个例子作为一个题目来研究就好),代码如代码段4:

代码段4:

class A(object):

def __init__(self):

print "enter A"

print "leave A"

class B(object):

def __init__(self):

print "enter B"

print "leave B"

class C(A):

def __init__(self):

print "enter C"

super(C, self).__init__()

print "leave C"

class D(A):

def __init__(self):

print "enter D"

super(D, self).__init__()

print "leave D"

class E(B, C):

def __init__(self):

print "enter E"

B.__init__(self)

C.__init__(self)

print "leave E"

class F(E, D):

def __init__(self):

print "enter F"

E.__init__(self)

D.__init__(self)

print "leave F"

>>> f = F()

enter F

enter E

enter B

leave B

enter C

enter D

enter A

leave A

leave D

leave C

leave E

enter D

enter A

leave A

leave D

leave F

明显地,类A和类D的初始化函数被重复调用了2次,这并不是我们所期望的结果!我们所期望的结果是最多只有类A的初始化函数被调用2次——其实这是多继承的类体系必须面对的问题。我们把代码段4的类体系画出来,如下图:

object

| /

| A

| / |

B C D

/ / |

E |

/ |

F

按我们对super的理解,从图中可以看出,在调用类C的初始化函数时,应该是调用类A的初始化函数,但事实上却调用了类D的初始化函数。好一个诡异的问题!

详情请点击:Python中的super用法详解_python_脚本之家​www.jb51.net

注意点:

1.__init__是析构函数,也就是类被实例化(生成对象)之后默认加载的内容,常用于初始化类。

2.__init__是函数只加在一次,且在类运行时首先运行。

3.#通过super初始化父类,__init__()函数无self,若直接QtWidgets.QWidget.__init__(self),括号里是有self的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值