前言
在Python中,super() 并不是简单地“调用父类”的方法,而是用于调用“MRO(Method Resolution Order,方法解析顺序)中的下一个类”的方法。MRO是指Python在查找类层次结构中的方法时所遵循的顺序。
MRO的工作原理
Python中的MRO遵循C3线性化算法,这是一种广泛使用的深度优先左至右的线性化策略。它确保每个类在MRO中只出现一次,并且如果一个类继承自多个父类,那么这些父类的顺序也是确定的。
示例
假设我们有一个类层次结构如下:
class A:
def do_something(self):
print("A doing something")
class B(A):
def do_something(self):
print("B doing something")
super().do_something()
class C(A):
def do_something(self):
print("C doing something")
super().do_something()
class D(B, C):
def do_something(self):
print("D doing something")
super().do_something()
在这个例子中,D 继承自 B 和 C,并且 B 和 C 都继承自 A。当我们调用 D 中的 do_something 方法时,super().do_something() 会按照MRO的顺序调用下一个类的方法。
查看MRO
可以使用 __mro__ 属性来查看类的MRO:
print(D.__mro__)
输出:
(,,,,)
调用MRO中的下一个方法
在 D 的 do_something 方法中,super().do_something() 会调用 B 类中的 do_something 方法,而不是直接调用 A 类的方法。这是因为 D 的MRO中下一个类是 B。
完整代码如下:
class A:
def do_something(self):
print("A doing something")
class B(A):
def do_something(self):
print("B doing something")
super().do_something()
class C(A):
def do_something(self):
print("C doing something")
super().do_something()
class D(B, C):
def do_something(self):
print("D doing something")
super().do_something()
d = D()
d.do_something()
输出:
D doing something
B doing something
C doing something
A doing something
可以看到,D 的 do_something 方法首先打印 "D doing something",然后调用 B 的方法,依次类推,直到调用 A 的方法。
总结
因此,super() 实际上调用的是MRO中定义的下一个类的方法,而不是简单地调用直接的父类方法。这种方法保证了多继承情况下方法调用的一致性和可预测性。
高阶示例
使用元类(Metaclass)动态创建类
元类可以用来控制类的创建过程。下面的示例展示了如何使用元类来动态创建具有特定行为的类。
class AutoStrMeta(type):
def __new__(cls, name, bases, attrs):
attrs['__str__'] = lambda self: f"{name}({', '.join(f'{k}={v}' for k, v in vars(self).items())})"
return super().__new__(cls, name, bases, attrs)
class MyClass(metaclass=AutoStrMeta):
def __init__(self, x, y):
self.x = x
self.y = y
obj = MyClass(10, 20)
print(obj) # 输出: MyClass(x=10, y=20)
使用描述符协议实现属性验证
描述符协议允许你自定义类属性的行为。下面的示例展示了如何使用描述符来实现属性的验证。
class PositiveInteger:
def __init__(self, initial_value=None):
self.value = initial_value
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
if not isinstance(value, int) or value < 0:
raise ValueError("Value must be a positive integer.")
self.value = value
class MyClass:
count = PositiveInteger()
def __init__(self, count):
self.count = count
obj = MyClass(10)
print(obj.count) # 输出: 10
obj.count = -5 # 抛出 ValueError
使用类装饰器自动注册子类
类装饰器可以用来自动注册子类,以便在创建对象时可以根据某种条件选择合适的子类。
registry = []
def register_class(cls):
registry.append(cls)
return cls
@register_class
class MyClass1:
def method(self):
return "MyClass1"
@register_class
class MyClass2:
def method(self):
return "MyClass2"
def create_instance(index):
return registry[index]()
instance1 = create_instance(0)
instance2 = create_instance(1)
print(instance1.method()) # 输出: MyClass1
print(instance2.method()) # 输出: MyClass2
使用__slots__和__getstate__/__setstate__优化序列化
__slots__ 可以减少内存占用,而 __getstate__ 和 __setstate__ 则可以控制对象的序列化和反序列化。
import pickle
class MyClass:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
def __getstate__(self):
return {'x': self.x, 'y': self.y}
def __setstate__(self, state):
self.x = state['x']
self.y = state['y']
obj = MyClass(10, 20)
serialized = pickle.dumps(obj)
deserialized = pickle.loads(serialized)
print(deserialized.x) # 输出: 10
print(deserialized.y) # 输出: 20
使用__new__和__init__实现单例模式
单例模式确保一个类只有一个实例,并提供一个全局访问点。下面的示例展示了如何使用 __new__ 和 __init__ 来实现单例模式。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, value):
if not hasattr(self, '_initialized'): # 防止多次初始化
self.value = value
self._initialized = True
singleton1 = Singleton('first')
singleton2 = Singleton('second')
print(singleton1.value) # 输出: first
print(singleton2.value) # 输出: first
print(singleton1 is singleton2) # 输出: True
最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】
软件测试面试文档
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。