Files
Python_CookBook_repo/8.类与对象/7.调用父类中的方法.py
2025-09-10 16:12:45 +08:00

120 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 要调用父类中的方法可以使用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)