Files
Python_CookBook_repo/8.类与对象/7.调用父类中的方法.py

120 lines
3.7 KiB
Python
Raw Normal View History

2025-09-10 16:12:45 +08:00
# 要调用父类中的方法可以使用super完成
class A:
def spam(self):
print('A.spam')
class B(A):
def spam(self):
print('B.spam')
super().spam()
# super的另一种常用方法是调用父类的__init__方法来确保父类被正确初始化了
class A:
def __init__(self):
self.x = 0
class B(A):
def __init__(self):
super().__init__()
self.y = 1
# 还有一种情况就是你覆写了类中的方法此时你可以调用super函数来使用原方法
class Proxy:
def __init__(self, obj):
self._obj = obj
def __getattr__(self, name):
return getattr(self._obj, name)
def __setattr__(self, name, value):
if name.startwith('_'):
super().__setattr__(name, value)
else:
setattr(self._obj, name, value)
# Python中的类继承
# 有些人有坏习惯,在子类中直接调用父类的方法,这在大部分时候能行
class Base:
def __init__(self):
print('Base.__init__')
class A(Base):
def __init__(self):
Base.__init__(self)
print('A.__init__')
# 但是如果这涉及到多重继承,那就会导致暴毙现象
class BaseV2:
def __init__(self):
print('Base.__init__')
class A1(BaseV2):
def __init__(self):
BaseV2.__init__(self)
print('A1.__init__')
class A2(BaseV2):
def __init__(self):
BaseV2.__init__(self)
print('A2.__init__')
class B1(A1, A2):
def __init__(self):
A1.__init__(self)
A2.__init__(self)
print('B1.__init__')
# 上面的继承关系就是标准的钻石继承,如果运行代码就会出现神奇魔法
b1 = B1()
# 哇Base的__init__函数被调用了两次这在一些场景下可能会导致麻烦但如果使用super(),那就不会有这么多事了
class BaseV3:
def __init__(self):
print('Base.__init__')
class B1(BaseV3):
def __init__(self):
super().__init__()
print('B1.__init__')
class B2(BaseV3):
def __init__(self):
super().__init__()
print('B2.__init__')
class C1(B1, B2):
def __init__(self):
super().__init__()
print('C1.__init__')
# 这样的继承是健康的每个init函数只被调用了一次
c1 = C1()
# 这是为啥嘞每个类Python都会计算得出一个方法解析顺序列表MRO在这个列表中会简单的对所有基类进行线性排列
print(C1.__mro__)
# MRO列表又是怎么确定的呢Python使用了一种叫C3线性化处理的技术这是一种归并排序且满足三个约束
# 1.先检查子类再检查父类; 2.多个父类时按照列表顺序依次检查; 3.如果下一个待选的类出现了两个合法的选择,就从第一个父类中选取
# C3有点麻烦但是计算的时候可以使用Python2.2更新的新式类MRO方法
# 从左至右的深度优先遍历,但是如果遍历中出现重复的类,只保留最后一个,之后再根据去重前类的出现顺序排序
# 使用super函数时,会从MRO列表中的下一个类中搜索方法,只要每一个重定义过的方法都使用了super(),super就能保证让这个方法只被调用一次
# super(a, b)函数的本质是获取类a在类b的MRO列表中a的下一个类
# 但是这样也可能出现以下意想不到的孝bug
class D:
def spam(self):
print('D.spam')
super().spam()
class D1:
def spam(self):
print('D1.spam')
class D2(D, D1):
pass
d = D2()
d.spam()
# 这是由于MRO列表导致的super函数bug,这三个类的MRO列表应该是[D2, D, D1], super去找了D1中的方法
# 要避免遇到麻烦,最好遵守下面两点
# 1.确保所有的类中都实现了相同签名的调用; 2.确保你要调用的方法在顶层被实现(例子中为D2)