[python]面向对象三大基本特性---继承
继承是面向对象编程的一个重要的方式,通过继承,子类可以复用父类里面的属性或者方法,如果需要,子类也可以提供自
己的属性和方法,属性或者方法名相同的情况下子类优先使用自己的属性或者方法。
Python中子类调用父类的方法有两种方法能够实现(两者不要混用):
调用父类构造方法:父类名.方法名(self, *args, **kwargs)
或者使用super函数:super(子类名, self).方法名(self, *args, **kwargs),
另外,以上两种方法在单继承上用法基本相同。
关于参数,
super() 方法参数的说明,第一个参数是当前类,即子类,第二个参数固定 self,表示当前的实例对象,在 Python2 中
必须加参数调用,而 python3 中可以省略参数。
其他注意点:
私有的属性、方法,不会被子类继承,也不能被访问
一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用。
super调用父类方法和使用父类名.方法名在多继承上用法不同,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次。
代码如下(测试在python3.7环境下进行):
使用父类名.方法名:
class A(object):
def __init__(self):
print("init A Class")
class B(A):
def __init__(self):
print("init B class")
A.__init__(self)
class C(A):
def __init__(self):
print("init C class")
A.__init__(self)
class D(B,C):
def __init__(self):
print("init D class")
B.__init__(self)
C.__init__(self)
d = D()
print(D.__mro__) # 可以查看D类的对象搜索方法时的先后顺序,与怎么调用父类方法无关
结果为:
--------------------------------------------------------------------------------
init D class
init B class
init A Class
init C class
init A Class
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
--------------------------------------------------------------------------------
从结果中可以看到classA被初始化了两次, 这不是期望的结果,在实际的应用中会造成错误,super函数就是为了这种情
况而存在的,防止父函数被多次初始化。
使用super调用父类方法:
class A(object):
def __init__(self):
print("init A Class")
class B(A):
def __init__(self):
print("init B class")
super(B, self).__init__()
class C(A):
def __init__(self):
print("init C class")
super(C, self).__init__()
class D(B,C):
def __init__(self):
print("init D class")
super(D, self).__init__()
d = D()
print(D.__mro__) # 可以查看D类的对象搜索方法时的先后顺序
结果为:
--------------------------------------------------------------------------------
init D class
init B class
init C class
init A Class
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
--------------------------------------------------------------------------------
多重继承:
在python中一个类能继承自不止一个父类,这叫做python的多重继承(Multiple Inheritance )。也就是我们可以为一个类同时指定多个父类,可以在类名的()后边添加多个类,来实现多重继承。
通过多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法,
但是,
在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂,多个父类互相继承多个父类的父类会导致问题,关于这个问题本文暂时不多讨论,以后会慢慢补充上去。
如果多个父类中有同名的方法,前边父类的方法会覆盖后边父类的方法。
注: MRO(method resolution order)—— 方法搜索顺序,Python 中针对类提供了一个内置属性__mro__,可以查看方
法搜索顺序,主要用于在多继承时判断方法、属性的调用顺序和路径,与怎么调用父类方法无关;
【新式类内置了mro方法,经典类则没有该内置该方法;在Python 3.x中取消了经典类,默认都是新式类,并且不必显式的 继承object,即在Python 3.x都是新式类,而在Python2.x中,默认都是经典类,只有显式继承了object才是新式类】
class.__mro__
This attribute is a tuple of classes that are considered when looking for base classes during method resolution.
class.mro()
This method can be overridden by a metaclass to customize the method resolution order for its instances. It is called at class instantiation, and its result is stored in __mro__.
另外,这是一个调用父类的父类的测试:
class A(object):
def __init__(self):
print("init A Class")
class B(A):
def __init__(self):
super(A, self).__init__()
print("init B class")
class C(A):
def __init__(self):
super(A, self).__init__()
print("init C class")
class D(B,C):
def __init__(self):
super(B, self).__init__()
super(C, self).__init__()
print("init D class")
d = D()
print(D.__mro__)
结果为:
--------------------------------------------------------------------------------
init D class
init C class
init A Class
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
--------------------------------------------------------------------------------
class A(object):
def __init__(self):
print("init A 开始被调用")
print( "init A Class")
print("init A 结束被调用")
class B(A):
def __init__(self):
print("init B 开始被调用")
print("init B class")
super(B, self).__init__()
print("init B 结束被调用")
class C(A):
def __init__(self):
print("init C 开始被调用")
print("init C class")
super(C, self).__init__()
print("init C 结束被调用")
class D(B,C):
def __init__(self):
print("init D 开始被调用")
print ("init D class")
super(D, self).__init__()
print("init D 结束被调用")
class E(A):
def __init__(self):
print("init E 开始被调用")
print ("init E class")
super(E, self).__init__()
print("init E 结束被调用")
class F(E,D):
def __init__(self):
print("init F 开始被调用")
print ("init F class")
super(F, self).__init__()
print("init F 结束被调用")
f = F()
结果:
--------------------------------------------------------------------------------
init F 开始被调用
init F class
init E 开始被调用
init E class
init D 开始被调用
init D class
init B 开始被调用
init B class
init C 开始被调用
init C class
init A 开始被调用
init A Class
init A 结束被调用
init C 结束被调用
init B 结束被调用
init D 结束被调用
init E 结束被调用
init F 结束被调用
(<class '__main__.F'>, <class '__main__.E'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
--------------------------------------------------------------------------------
若改为
class A(object):
def __init__(self):
print("init A 开始被调用")
print( "init A Class")
print("init A 结束被调用")
class B(A):
def __init__(self):
print("init B 开始被调用")
print("init B class")
super(B, self).__init__()
print("init B 结束被调用")
class C(A):
def __init__(self):
print("init C 开始被调用")
print("init C class")
super(C, self).__init__()
print("init C 结束被调用")
class D(B,C):
def __init__(self):
print("init D 开始被调用")
print ("init D class")
super(D, self).__init__()
print("init D 结束被调用")
class E(A):
def __init__(self):
print("init E 开始被调用")
print ("init E class")
super(E, self).__init__()
print("init E 结束被调用")
class F(D,E):
def __init__(self):
print("init F 开始被调用")
print ("init F class")
super(F, self).__init__()
print("init F 结束被调用")
f = F()
则结果:
--------------------------------------------------------------------------------
init F 开始被调用
init F class
init D 开始被调用
init D class
init B 开始被调用
init B class
init C 开始被调用
init C class
init E 开始被调用
init E class
init A 开始被调用
init A Class
init A 结束被调用
init E 结束被调用
init C 结束被调用
init B 结束被调用
init D 结束被调用
init F 结束被调用
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.A'>, <class 'object'>)
--------------------------------------------------------------------------------
这是在Python 3.7环境下:
--------------------------------------------------------------------------------
Python 3.7.2 on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class X(object):
... pass
...
>>>
>>> class Y(object):
... pass
...
>>>
>>> class G(X, Y):
... pass
...
>>>
>>> class E(G):
... pass
...
>>> class D(G):
... pass
...
>>>
>>> class C(E):
... pass
...
>>>
>>> class B(D):
... pass
...
>>> class A(B, C):
... pass
...
>>>
>>> print(A.__mro__)
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.G'>, <class '__main__.X'>, <class '__main__.Y'>, <class 'object'>)
--------------------------------------------------------------------------------
这是在Python 2.7环境下:
--------------------------------------------------------------------------------
Python 2.7.13 on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class X(object):
... pass
...
>>>
>>> class Y(object):
... pass
...
>>>
>>> class G(X, Y):
... pass
...
>>>
>>> class E(G):
... pass
...
>>> class D(G):
... pass
...
>>>
>>> class C(E):
... pass
...
>>>
>>> class B(D):
... pass
...
>>> class A(B, C):
... pass
...
>>> print(A.__mro__)
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.G'>, <class '__main__.X'>, <class '__main__.Y'>, <type 'object'>)
--------------------------------------------------------------------------------
根据以上几个案例测试,大致可以总结:
简单来说,mro调用顺序按照从左往右的使用深度优先进行,但若有共同的祖先类,则在该祖先类之前从左往右的使用深度
优先进行调用,之后也是按照从左往右的使用深度优先顺序进行该祖先类之后的调用。
关于MRO推导新算法---C3算法,现在我理解不够深入,本文暂时不多讨论,以后会慢慢补充上去。
摘录几个讲C3算法的如下:
【Python】C3算法 - foreverlove~ - 博客园 https://www.cnblogs.com/bashaowei/p/8508276.html
Python3中的C3算法:多继承查找规则_Python_NO FATE-CSDN博客
https://blog.csdn.net/u011467553/article/details/81437780
多继承带来的菱形问题 - 江湖有梦 - 博客园
https://www.cnblogs.com/bailongcaptain/p/12670533.html
彻底掌握python类MRO(方法解析顺序)————原文章merge移除规律有点不对_Joohn2015的博客-CSDN博客
https://blog.csdn.net/Joohn2015/article/details/85097196
统一声明:关于原创博客内容,可能会有部分内容参考自互联网,如有原创链接会声明引用;如找不到原创链接,在此声明如有侵权请联系删除哈。关于转载博客,如有原创链接会声明;如找不到原创链接,如果有哪些问题、有些谬误、有哪些不妥或者侵犯到您的权益的地方,可以联系我,我马上修改。

浙公网安备 33010602011771号