python中super用法
目录
前言
在python
继承的时候经常会遇到super
这个东西,搞得不是太明白,写下这篇博文记录一下。我这里用的是python3
版本。
一. super是什么
先来看下super
是什么,怎么用的,具体后面介绍?
super
是一个内置函数,用于调用父类(超类)的方法。它提供了一种方便的方式来调用父类的方法,而不需要显式地指定父类的名称。super
函数通常在子类的方法中使用。当你在子类中重写一个方法时,可以使用super函数来调用父类的相同方法。这样可以在不破坏继承关系的前提下,扩展或修改父类的行为。super
函数接受两个参数:子类的类名和子类的实例,即super(子类类名,self).__init__()
它返回一个特殊的对象,该对象可以用于调用父类的方法。通过super
函数返回的对象,可以在子类中直接调用父类的方法,而无需显式指定父类的名称。在python3
中已经简化了这种写法:直接写成super().__init__()
。
看个例子
class ParentClass: def __init__(self): self.parent_var = 10 def some_method(self): print("ParentClass method")class ChildClass(ParentClass): def __init__(self): super().__init__() # 调用父类的初始化方法 self.child_var = 20 def some_method(self): super().some_method() # 调用父类的方法 print("ChildClass method")child_obj = ChildClass()child_obj.some_method()
把上面的代码改成类名继承看下:
class ParentClass: def __init__(self): self.parent_var = 10 def some_method(self): print("ParentClass method")class ChildClass(ParentClass): def __init__(self): ParentClass.__init__(self) # 调用父类的初始化方法 self.child_var = 20 def some_method(self): ParentClass.some_method(self) # 调用父类的方法 print("ChildClass method")child_obj = ChildClass()child_obj.some_method()
输出:
ParentClass methodChildClass method
通过对比可以看到通过super
可以直接替代类名从而简便继承方式。其实super
对于普通函数的继承很好理解,就是直接通过super().xxx()
即可调用父类的方法。我们下面重点介绍下经常让人困惑的super().__init__()
。
二.super().__ init__ ()
在理解super().__ init__ ()
的时候也可以直接把他当做继承普通的函数一样,只不过这里是继承父类的构造函数。既然是继承父类的构造函数,那么在继承的时候同样出现一种现象,那就是重写(有些人叫覆盖,个人感觉叫做重写更严谨),重写顾名思义就是父类已经有了这个函数了,子类中又写了一遍。根据强龙不压地头蛇的原则,那么在使用的时候如果发生了重写,就要以子类的函数为准。看个例子:
class A: def __init__(self): print("调用A")class B(A): def __init__(self): print("调用B")b = B()
输出:
调用B
上面的代码可以发现,虽然B
继承了A
,但是构造函数重写了,所以在调用实例化B
的时候调用的还是B
本身的构造函数,可以理解为父类的构造函数被覆盖了。如果我还想调用父类的怎么办呢,如果你能想到继承,说明你基本上已经明白了,我们直接看例子:
class A: def __init__(self): print("调用A")class B(A): def __init__(self): super().__init__() print("调用B")b = B()
输出:
调用A调用B
再来看个稍微复杂点的例子:
class ParentClass: def __init__(self, x): self.parent_var = x def some_method(self): print("ParentClass method")class ChildClass(ParentClass): def __init__(self, x, y): super().__init__(x) # 继承父类的构造函数 self.child_var = ychild_obj = ChildClass(10, 20)print(child_obj.parent_var) # 访问继承的父类属性print(child_obj.child_var) # 访问子类属性
输出:
1020
子类中并没有parent_var这个属性,但是可以通过继承父类的构造函数获取到这个属性。
三. 继承顺序
当发生多继承的时候他的顺序是什么样的,如下面的一段代码C
这个子类在继承父类的初始化函数的时候到底继承的是A
的还是B
的?
class A: def __init__(self): print('A')class B: def __init__(self): print('B')class C(A, B): def __init__(self): print('C') super().__init__()c = C()
我们看一下输出结果是什么:
CA
为什么输出的是C
,A
呢?这里涉及到Python
中的菱形继承。菱形继承的原则是继承的两个父类时并列的。按照继承的父类从左至右的顺序查找的,如果在当前类中找到方法,就直接执行,不再进行搜索,如果没有找到就查找下一个继承的父类中是否有对应的方法,如果找到,就直接执行,不再搜索,如果找到最后一个类,还没有找到方法,程序报错。
根据上面的原则,我们来看一个复杂点的多继承:
class A: def __init__(self): print('A')class B(A): def __init__(self): print('B') super().__init__()class C(A): def __init__(self): print('C') super().__init__()class D(A): def __init__(self): print('D') super().__init__()class E(B, C): def __init__(self): print('E') super().__init__()class F(C, D): def __init__(self): print('F') super().__init__()class G(E, F): def __init__(self): print('G') super().__init__()g = G()
输出:
GEBFCDA
根据输出结果可以看到G
继承自E
, F
是并列的,初始化的时候不会先把E
初始化完毕才初始化F
。也可以通过Python
自带的__mro__
查看一下继承顺序:
print(G.__mro__)
输出:
(<class '__main__.G'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.F'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
至此关于super
的基本介绍就已经讲完了,如有错误,敬请指正!
来源地址:https://blog.csdn.net/qq_38683460/article/details/131141587
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341