python super真的是调用父类吗?

前言

在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%免费】

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值