赞
踩
假如你了解面对对象的继承会发现,当我们子类继承一个父类的时候,在子类中重写与父类同名的方法,那么python在这个子类调用这个同名方法时,会使用子类的方法。即子类的方法会把父类的方法覆盖掉(c++则需要定义虚函数virtual)。那有什么方法可以在子类中调用父类的同名方法呢?
class Base { public: Base() { m_A = 100; } void func() { cout << "Base - func()调用" << endl; } void func(int a) { cout << "Base - func(int a)调用" << endl; } public: int m_A; }; class Son : public Base { public: Son() { m_A = 200; } //当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数 //如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域 void func() { cout << "Son - func()调用" << endl; } public: int m_A; }; void test01() { Son s; cout << "Son下的m_A = " << s.m_A << endl; cout << "Base下的m_A = " << s.Base::m_A << endl; s.func(); s.Base::func(); s.Base::func(10); } int main() { test01(); system("pause"); return EXIT_SUCCESS; }
Base::
的作用域来实现在子类中调用和父类同名的成员那python是如何处理的呢?
class Animal(object): def eat(self): print("动物吃东西") class Cat(Animal): def eat(self): print("猫吃东西") def eat1(self): Animal.eat(self) if __name__ == '__main__': c = Cat() c.eat() c.eat1() >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 猫吃东西 动物吃东西
super() 函数是用于调用父类(超类)的一个方法。
super(type[, object-or-type])
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
class Male(Person):
def __init__(self, name, age, height):
super().__init__(name, age)
self.height = height
if __name__ == '__main__':
m = Male('xiaoming', 18, 172)
__init__
函数呢? 原因很简单,python的构造函数不同于c++语言构造函数使用的是类名,它的构造函数统一采用__init__
这个函数名,并且__init__
也是我们平时最常用的魔法方法,当我们在__init__
对子类的成员做初始化时,发现父类中已经实现这个初始化的操作了,我们就可以直接用调用父类的构造函数来对我们的属性做初始化。class Person(object): def __init__(self, name, age): self.name = name self.age = age class Male(Person): def __init__(self, name, age, height): super().__init__(name, age) self.height = height print(super()) if __name__ == '__main__': m = Male('xiaoming', 18, 172) >>>>>>>>>>>>>>>>>>>>>>>>> <super: <class 'Male'>, <Male object>>
<super: <class 'Male'>, <Male object>>
,可以看到在子类中的构造函数打印出来发现,super()的第一个参数为class,第二个参数为objectclass Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
class Male(Person):
def __init__(self, name, age, height):
super(Male, self).__init__(name, age)
self.height = height
if __name__ == '__main__':
m = Male('xiaoming', 18, 172)
class Person(object): def __init__(self, name, age): self.name = name self.age = age class Male(Person): def __init__(self, name, age, height): super(Male, self).__init__(name, age) # Person().__init__(name, age) self.height = height print(Male.mro()) if __name__ == '__main__': m = Male('xiaoming', 18, 172) >>>>>>>>>>>>>>>>>>>>>>>>>>> [<class '__main__.Male'>, <class '__main__.Person'>, <class 'object'>]
我直接给出结论:我们首先需要在第二个参数self找到当前的mro(当前所处类的mro),从上面可以看到当前的mro为 Male->Person->object
,并且从第一个参数的所处的mro往前找,即Male往前找就是Person,然后看到Person有没有这个__init__
函数,如果有这个函数则将父类绑定到self,实现父类构造函数初始化子类属性。
class Person(object): def __init__(self, name, age): self.name = name self.age = age class Male(Person): def __init__(self, name, age, height): # super(Male, self).__init__(name, age) Person.__init__(self, name, age) self.height = height if __name__ == '__main__': m = Male('xiaoming', 18, 172) print(m.__dict__) {'name': 'xiaoming', 'age': 18, 'height': 172}
class Person(object): def __init__(self, name, age): self.name = name self.age = age class Male(Person): def __init__(self, name, age, height): super(Male, self).__init__(name, age) # Person.__init__(self, name, age) self.height = height if __name__ == '__main__': m = Male('xiaoming', 18, 172) print(m.__dict__)
上面两行代码都输出{'name': 'xiaoming', 'age': 18, 'height': 172}
,说明Person.__init__(self, name, age)
== super(Male, self).__init__(name, age)
,实现的机制就是mro寻找
class Animal(object): def __init__(self, name): self.name = name class Person(Animal): def __init__(self, name, age): super(Person, self).__init__(name) self.age = age class Male(Person): def __init__(self, name, age, height): super(Person, self).__init__(name) #super(Male, self).__init__(name, age) self.height = height if __name__ == '__main__': m = Male('xiaoming', 18, 172) print(m.__dict__) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> {'name': 'xiaoming', 'height': 172}
Male->Person->Animal
,然后我们再第一个参数传入Person,此时super会从Person开始往上找到Animal,这样我们会用Animal的构造函数给Male这个类做初始化,直接跳过了Person这个类的构造函数class Animal(object): def __init__(self, name): self.name = name class Person(Animal): def __init__(self, name, age): super(Person, self).__init__(name) self.age = age class Male(Person): def __init__(self, name, age, height): # super(Person, self).__init__(name) #super(Male, self).__init__(name, age) self.height = height if __name__ == '__main__': m = Male('xiaoming', 18, 172) super(Male,m).__init__('xiaoming',118) print(m.__dict__) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> {'height': 172, 'name': 'xiaoming', 'age': 118}
甚至可以在类外使用super函数对子类进行初始化
,传入类的名称和实例化的对象就行class Animal(object): def say(self): print("动物在叫") class Cat(Animal): def say(self): super(Cat, self).say() class Dog(Animal): def say(self): print("狗在叫") print(CatDog.mro()) class CatDog(Cat, Dog): def say(self): super(CatDog, self).say() if __name__ == '__main__': cat_dog = CatDog() cat_dog.say() >>>>>>>>>>>>>>>>>>>>>>>>>>>> 狗在叫 [<class '__main__.CatDog'>, <class '__main__.Cat'>, <class '__main__.Dog'>, <class '__main__.Animal'>, <class 'object'>]
启示:避免在多继承中使用super
本文首先引出了继承中存在的问题如何在子类调用父类的同名函数,然后引出c++和python做法,python中super的常见用法,super()两个参数的含义,super在多继承出现的问题
https://www.bilibili.com/video/BV1FL4y1E7xK
https://www.geeksforgeeks.org/python-super/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。