友链提交
请认真填写以下信息,谢谢!

博客信息

HoshinoAi
(请填写完整的网址,例如:https://www.example.com)
(贵站展示本站链接的页面地址,一般是友链页面,填写后将自动验证友链关系有效性)
(用于抓取文章)
(用于接收通知)
菜单
本页目录

三、继承与多态

3.1 继承

3.1.1 Python中继承的概念

在Python中,继承是一种面向对象编程的特性,它允许我们定义一个继承一个或多个其他类的属性和方法的新类。继承有助于代码的复用,可以让我们基于已有的类创建新的类,而不必从头开始编写。

3.1.1.1 基本术语

  • 基类(Base class) / 父类(Parent class):被继承的类,提供了属性和方法供子类使用。
  • 派生类(Derived class) / 子类(Child class):从基类继承属性和方法的类。

3.1.1.2 单继承

class Parent:
    def __init__(self, name):
        self.name = name

    def show_name(self):
        print(f"The name is {self.name}")

class Child(Parent):
    pass

c = Child("Alice")
c.show_name()  # 输出: The name is Alice

在上面的例子中,Child类继承了Parent类,因此它可以使用Parent类中的show_name方法。

3.1.1.3 多继承

class Mother:
    def __init__(self, mother_name):
        self.mother_name = mother_name

class Father:
    def __init__(self, father_name):
        self.father_name = father_name

class Child(Mother, Father):
    def __init__(self, mother_name, father_name, child_name):
        Mother.__init__(self, mother_name)
        Father.__init__(self, father_name)
        self.name = child_name

    def show_names(self):
        print(f"Child Name: {self.name}")
        print(f"Mother Name: {self.mother_name}")
        print(f"Father Name: {self.father_name}")

c = Child("Martha", "John", "Alice")
c.show_names()

在多继承中,如果多个父类中有相同名称的方法,则按照MRO(方法解析顺序)来决定调用哪个类的方法。

MRO(Method Resolution Order,方法解析顺序) 面向对象编程中的一个概念,特别是在多继承的情况下,它定义了在继承体系中解析方法的顺序。MRO 对于确保正确的方法覆盖(即子类中的方法覆盖父类中的同名方法)以及处理菱形继承(一个类从多个类继承,而这些类又有一个共同的祖先)等问题至关重要。

在Python中,MRO遵循C3线性化算法(C3 superclass linearization)。C3算法可以保证几个重要的特性:

  • 子类会先于父类被检查。
  • 如果多个父类存在,它们将按照它们在类定义中的顺序被检查。
  • 如果对某个类存在多个继承路径,将选择第一个路径。

3.1.1.4 方法重写

class Parent:
    def show(self):
        print("This is the Parent class show method.")

class Child(Parent):
    def show(self):
        print("This is the Child class show method.")

c = Child()
c.show()  # 输出: This is the Child class show method.

在上面的例子中,Child类中的show方法重写了Parent类中的show方法。

3.1.1.5 调用父类方法

class Parent:
    def __init__(self):
        print("Parent init")

    def say_hello(self):
        print("Hello from Parent")

class Child(Parent):
    def __init__(self):
        super().__init__()  # 调用父类的构造函数
        print("Child init")

    def say_hello(self):
        super().say_hello()  # 调用父类的方法
        print("Hello from Child")  # 执行子类自己的代码

# 创建Child类的实例
c = Child()

# 调用子类的方法
c.say_hello()

3.1.2 处理银行账户简易的转账算法(继承版本)

# 定义BankAccount基类
class BankAccount:
    # 类属性,用于存储所有账户的共同利率
    interest_rate = 0.03  # 假设年利率为3%

    # 构造函数,用于初始化银行账户的属性
    def __init__(self, account_number, owner, balance=0.0):
        self.account_number = account_number  # 账户号码
        self.owner = owner                    # 账户所有者
        self.balance = balance                # 账户余额

    # 存款方法,向账户中存入指定金额
    def deposit(self, amount):
        if amount > 0:
            self.balance += amount  # 增加账户余额
            print(f"{self.owner} 存款 {amount:.2f} 元。账户余额: {self.balance:.2f} 元")
        else:
            print("存款金额必须为正数。")

    # 取款方法,从账户中取出指定金额
    def withdraw(self, amount):
        if 0 < amount <= self.balance:
            self.balance -= amount  # 减少账户余额
            print(f"{self.owner} 取款 {amount:.2f} 元。账户余额: {self.balance:.2f} 元")
        else:
            print("无效的取款金额。")

    # 显示账户余额的方法
    def get_balance(self):
        print(f"账户 {self.account_number} ({self.owner}) 的余额是 {self.balance:.2f} 元")

    # 转账方法,将指定金额从当前账户转账到另一个账户
    def transfer(self, target_account, amount):
        if isinstance(target_account, BankAccount):
            if 0 < amount <= self.balance:
                self.withdraw(amount)  # 从当前账户取款
                target_account.deposit(amount)  # 向目标账户存款
                print(f"从 {self.owner} 账户向 {target_account.owner} 账户转账 {amount:.2f} 元。")
            else:
                print("无效的转账金额。")
        else:
            print("目标账户必须是一个 BankAccount 实例。")

    # 类方法,用于获取当前利率
    @classmethod
    def get_interest_rate(cls):
        return cls.interest_rate

    # 类方法,用于设置新的利率
    @classmethod
    def set_interest_rate(cls, new_rate):
        if new_rate >= 0:
            cls.interest_rate = new_rate  # 更新类属性
            print(f"新的利率已设置为:{new_rate}")
        else:
            print("利率不能为负数。")

    # 静态方法,用于计算利息
    @staticmethod
    def calculate_interest(balance, rate):
        return balance * rate  # 利息计算公式

# 定义SpecialBankAccount子类,继承自BankAccount
class SpecialBankAccount(BankAccount):
    # 构造函数,初始化基类属性并添加特殊属性
    def __init__(self, account_number, owner, balance=0.0, special_feature="VIP"):
        # 调用基类构造函数初始化基类属性
        super().__init__(account_number, owner, balance)
        # 添加新的特殊属性
        self.special_feature = special_feature

    # 显示特殊账户信息的方法
    def show_special_feature(self):
        # 打印账户的特殊属性
        print(f"账户 {self.account_number} ({self.owner}) 的特殊属性是:{self.special_feature}")

# 创建SpecialBankAccount实例
special_account = SpecialBankAccount('123456', 'Charlie', 1500.0)

# 执行一些操作
special_account.deposit(300.0)      # Charlie 存款 300 元
special_account.withdraw(150.0)     # Charlie 取款 150 元
special_account.get_balance()       # Charlie 查看余额
special_account.show_special_feature()  # 显示特殊属性

# 使用继承的类方法
print(f"当前利率:{SpecialBankAccount.get_interest_rate()}")  # 输出当前利率
SpecialBankAccount.set_interest_rate(0.05)  # 设置新的利率为5%

# 使用继承的静态方法
interest = SpecialBankAccount.calculate_interest(special_account.balance, SpecialBankAccount.get_interest_rate())
print(f"Charlie账户的利息:{interest:.2f} 元")  # 输出Charlie账户的利息

super(): 在Python中,super() 函数是用来调用父类(基类)的一个方法的。它是用来实现继承中的一种特性,即在子类中访问父类的方法

  • 调用父类的构造函数:在子类的构造函数中,使用 super() 来调用父类的构造函数,确保父类中的初始化代码得到执行。
  • 调用父类的方法:在子类中,如果你想调用父类中的某个方法,可以使用 super() 来实现。

3.2 多态

  • 编译时多态(静态多态):主要是通过函数重载或模板实现,这在Python中并不直接支持。
  • 运行时多态(动态多态):在运行时根据对象的实际类型来决定调用哪个方法,这是Python中实现多态的主要方式。

3.2.1 Python中的多态

3.2.1.1 Duck Typing

Python有一个著名的原则叫做“鸭子类型”(Duck Typing),即“如果它走起来像鸭子,叫起来也像鸭子,那么它就是鸭子”。这意味着在Python中,一个对象的类型并不重要,只要它拥有某个方法或属性,就可以调用该方法或属性,这就是一种多态的表现。

3.2.1.2 方法重写

在子类中重新定义从父类继承来的方法,这就是方法重写。当子类和父类存在相同的方法时,通过子类实例调用方法时会执行子类的方法,而不是父类的方法。

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "汪汪汪"

class Cat(Animal):
    def speak(self):
        return "喵喵喵"

def animal_speak(animal):
    print(animal.speak())

dog = Dog()
cat = Cat()

animal_speak(dog)  # 输出: 汪汪汪
animal_speak(cat)  # 输出: 喵喵喵

3.2.1.3 抽象基类(ABC)

Python提供了abc模块,允许创建抽象基类(Abstract Base Classes,ABCs)。抽象类不能被实例化,它只是用来定义子类应该实现的方法。

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "汪汪汪"

class Cat(Animal):
    def speak(self):
        return "喵喵喵"

3.2.1.3.1 元类

在Python中,元类(metaclass)是创建类的“类”。换句话说,就像类是创建对象的模板一样,元类是创建类的模板。

  • 元类是一个高级特性,通常只有在需要时才使用。
  • 在Python中,一切皆是对象,类本身也是对象,它是元类的实例。
  • 默认的元类:如果你没有显式地指定一个类的元类,Python会使用默认的元类,即type。type既可以作为函数使用,也可以作为元类使用。
class MyClass:
    pass

class MyClassWithExplicitMeta(type):
    pass

# 这两个类都是使用type作为元类创建的