python 面向对象: super()
python 关于 super 的使用
- 子类对象调用父类方法 :
super(B,b).hh()
- 子类中调用父类方法
- 显示调用:
B.hh(self)
- 使用super:
super(B,self).hh()
- 显示调用:
- super调用顺序:
__mro__
面试题: 子类对象调用父类方法
class AA(object):
def hh(self):
print('AA--------hh')
class BB(AA):
def hh(self):
print('BB--------hh')
b = BB()
在不改造类的前提下,使用对象b
调用AA
的hh()
方法。说实话我在python中没有这样调用过,但是隐约记得在java 中应该是直接用子类对象可以使用super
来调用到父类的方法,于是就回答面试官使用b.super(BB).hh()
真的虚啊~~~。面试官说就这样吧 ~~~ 。。。。写完文章后回过来看,自己真傻叉,我记得可以使用self.super()调用啊 ,其实该方法和在类中调用一样啊 !! 抱歉小白,大家会的直接略过!!
然后面试结束后回来自己,测试直接报错!!!,google,百度都没结果,反倒是一些super
烂大街的一些使用方法,使用了Python的自省也没有发现相关的函数,翻了大概半小时让我发现了,哈哈,上代码:
b.hh()
super(BB,b).hh()
输出:
BB--------hh
AA--------hh
就是使用super(BB,b).hh()
真的没用过不知道啊
子类中调用父类方法
烂大街用法
显示调用父类方法:
class AA(object):
def hh(self,msg):
print('AA----',msg)
class BB(AA):
def hh(self,msg):
AA.hh(self,msg)
print('BB----',msg)
b = BB()
b.hh('hello world')
输出:
AA---- hello world
BB---- hello world
成功调用到了父类的方法
使用关键字super()
调用父类方法:
class AA(object):
def hh(self,msg):
print('AA----',msg)
class CC(AA):
def hh(self,msg):
super(CC,self).hh(msg)
print('CC----',msg)
c = CC()
c.hh('hello world')
输出:
AA---- hello world
CC---- hello world
同样可以成功调用父类的方法
2种方式深入对比:
显示调用
已知有
class AA(object):
def hh(self,msg):
print('AA----',msg)
class BB(AA):
def hh(self,msg):
AA.hh(self,msg)
print('BB----',msg)
class CC(AA):
def hh(self,msg):
AA.hh(self,msg)
print('CC----',msg)
使用一:
class DD(BB,CC):
pass
d = DD()
d.hh('123')
输出:
AA---- 123
BB---- 123
使用二:
class DD(BB,CC):
def hh(self,msg):
BB.hh(self,msg)
CC.hh(self,msg)
d = DD()
d.hh('123')
输出:
AA---- 123
BB---- 123
AA---- 123
CC---- 123
优点:可以根据自己想要的结果具体调用某个函数,定制化程度高
缺点:共同父类的方法会被多次调用(某些情况下可能会出错,或者效率低下)
2种方式深入对比:
super调用
已知有:
class AA(object):
def hh(self,msg):
print('AA----',msg)
class BB(AA):
def hh(self,msg):
super(BB,self).hh(msg)
print('BB----',msg)
class CC(AA):
def hh(self,msg):
super(CC,self).hh(msg)
print('CC----',msg)
使用一:
class DD(BB,CC):
pass
d = DD()
d.hh('123')
输出:
AA---- 123
CC---- 123
BB---- 123
使用二:
class DD(BB,CC):
def hh(self,msg):
super(DD,self).hh(msg)
d = DD()
d.hh('123')
输出:
AA---- 123
CC---- 123
BB---- 123
你会发现,俩种使用方式输出的结果是一样的,且父类的函数只调用一遍
super调用顺序:
__mro__
在来点复杂的:
class A(object):
def go(self):
print('--A')
print("go A go!")
print('A--')
class B(A):
def go(self):
print('--B')
super(B,self).go()
print("go B go!")
print('B--')
class C(A):
def go(self):
print('--C')
super(C,self).go()
print("go C go!")
print('C--')
class D(B,C):
def go(self):
print('--D')
super(D,self).go()
print("go D go!")
print('D--')
d = D()
d.go()
print(D.__mro__)
print(d.__class__.mro())
输出:
--D
--B
--C
--A
go A go!
A--
go C go!
C--
go B go!
B--
go D go!
D--
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
调用顺序可谓是很诡异了。python 中对于多继承为了保证公共父类方法只被调用一次,使用了C3算法,根据某一顺序来执行继承链上的函数可以使用__mro__
查看;这是个类级别的函数.
可以看到继承链是 D-->B-->C-->A-->O输出时相当于逐链栈调用执行,等上层函数执行完才会继续执行下层函数,因此有如上输出
想深入了解super
的同学可以跳转:
“Python’s super() Considered Super!”
总结:
- 子类对象调用父类方法:
super(cls,self).fun(*arg)
- pyhton 子类调用父类方法 的俩种方案
- python 多继承调用顺序:画出继承图,从下到上,从左到右的顺序生成继承链,并以逐链栈调用的方式调用函数。
声明:
本人也是python 小白,对super()的使用也不是很熟练,掌握的并不好,如果上述内容有讲的不对的地方还请各位批评指点。将不胜感激,再次感谢~~~
参考资料:
- “Python’s super() Considered Super!”
-
Python的方法解析顺序(MRO)
关于super的讲解实在是太多,但都大同小异,钻研这俩篇就够了