大家都知道继承的目的是为了让子类可以使用父类的成员,实现代码的复用,但是在多继承中会出现各种问题:
class Father(object):
def __init__(self, name):
self.name = name
print("Im father")
class Son_1(Father):
def __init__(self, age, name):
self.age = age
Father.__init__(self, name)
print("Im Son_1")
class Son_2(Father):
def __init__(self, gender, name):
self.gender = gender
Father.__init__(self, name)
print("我是Son_2")
class GrandSon(Son_1, Son_2):
def __init__(self, name, age, gender):
Son_1.__init__(self, age, name)
Son_2.__init__(self, gender, name)
pass
grand_son = GrandSon("张三", 18, "男")
print(GrandSon.__mro__)
在上面的代码里,写了四个类,并且他们的继承关系非常清楚,Son1和Son2都继承自Father,而GrandSon刚好继承Son1,Son2,这样就是经典的菱形继承也叫钻石继承,
钻石继承带来的问题就是子类会调用多次父类的__init__方法,造成资源浪费和重复执行的问题。
上面的代码执行结果:这个grand_son = GrandSon(‘张三’, 18, ‘男’)一执行,打印了两次I am father
Im father
Im Son_1
Im father
我是Son_2
(<class '__main__.GrandSon'>, <class '__main__.Son_1'>, <class '__main__.Son_2'>, <class '__main__.Father'>, <class 'object'>)
那么我们如何解决呢?
答:利用super()调用父类的__init__
super()执行原理:
super(cls, instance)
1 super会先获取instance的__mro__列表,__mor__返回继承关系解析顺序列表
2 找到列表中cls的下一个类,返回
3 super()省略参数的时候只能调用__mro__列表中,cls的下一个类。
class Father(object):
def __init__(self, name):
self.name = name
print("Im father")
class Son_1(Father):
def __init__(self, name, age, gender):
self.age = age
super(Son_1, self).__init__(name, gender)
print("Im Son_1")
class Son_2(Father):
def __init__(self, name, gender):
self.gender = gender
super(Son_2, self).__init__(name)
print("我是Son_2")
class GrandSon(Son_1, Son_2):
def __init__(self, name, age, gender):
super(GrandSon, self).__init__(name, age, gender)
print("我是GrandSon")
grand_son = GrandSon("张三", 19, "男",)
print(GrandSon.__mro__)
用super()确实能够解决父类__init__重复调用的问题,但是这个传参是个麻烦,这样一来,Son1和Son2的参数需要根据grandSon的参数来变化,而且不能写死,这样非常不合理。
Im father
我是Son_2
Im Son_1
我是GrandSon
(<class '__main__.GrandSon'>, <class '__main__.Son_1'>, <class '__main__.Son_2'>, <class '__main__.Father'>, <class 'object'>)
如何解决传参困难的问题呢?
答:使用args,和**kwargs解决传参麻烦,具体args,和**kwargs是python里的特色,都是不定长参数,记得javascript里的不定长参数都保存在arguments对象里头,而他们都是相似的,只是*args是可变的位置参数列表,**kwargs是可变的关键字参数列表
class Father(object):
def __init__(self, name, *args, **kwargs):
self.name = name
print("我是父类__init__")
class Son_1(Father):
def __init__(self, name, age, *args, **kwargs):
print("我是Son_1的__init__")
super(Son_1, self).__init__(name, *args, **kwargs)
self.age = age
class Son_2(Father):
def __init__(self, name, gender, *args, **kwargs):
print("我是Son_2的__init__")
self.gender = gender
super(Son_2, self).__init__(name, *args, **kwargs)
class GrandSon(Son_1, Son_2):
def __init__(self, name, age, gender):
super(GrandSon, self).__init__(name, age, gender)
def say_hello(self):
print(self.name, self.age, self.gender)
grand_son = GrandSon("老王", 24, "男")
这样的结果才是我们要的,代码结果,妈妈再也不要担心我的传参问题了
我是Son_1的__init__
我是Son_2的__init__
我是父类__init__
作者:oldFeil
来源:CSDN
原文:https://blog.csdn.net/feilzhang/article/details/80443194
版权声明:本文为博主原创文章,转载请附上博文链接!