Skip to main content

Python 面向对象

Python 继承和多态

继承和多态是面向对象编程(OOP)的核心特性,它们使代码更灵活、可重用和模块化。在Python中,继承允许一个类从另一个类继承属性和方法,而多态允许不同的类以统一的方式处理。本章节将详细讲解Python中的继承和多态,帮助大家掌握这些概念。

1. 什么是继承?

继承(Inheritance) 是一种机制,允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。子类可以重用父类的代码,也可以添加新功能或修改已有功能。

例如,假设有一个表示“动物”的类,我们可以创建一个表示“狗”的子类,继承“动物”的通用属性和行为,同时添加狗特有的功能。

2. 定义和使用继承

在Python中,通过在类定义时将父类名放在括号中实现继承。子类会自动继承父类的所有属性和方法。

以下是一个简单的继承示例:

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

    def make_sound(self):
        print(f"{self.name} 发出声音")

class Dog(Animal):         # Dog 继承 Animal
    def make_sound(self):  # 重写父类方法
        print(f"{self.name} 说:汪汪!")

my_dog = Dog("Buddy")
my_dog.make_sound()        # 输出: Buddy 说:汪汪!

在这个例子中:

  • Dog 类继承了 Animal 类,通过 class Dog(Animal) 定义。
  • Dog 重写了 make_sound 方法,提供自己的实现。
  • 创建 Dog 实例时,会调用父类的 __init__ 方法,设置 name 属性。

3. 调用父类方法

子类可以调用父类的方法,使用 super() 函数。super() 允许子类访问父类的属性或方法,尤其是在子类需要扩展父类功能时。

以下是一个扩展父类 __init__ 方法的示例:

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

    def make_sound(self):
        print(f"{self.name} 发出声音")

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # 调用父类的 __init__
        self.breed = breed      # 添加子类特有属性

    def make_sound(self):
        print(f"{self.name} 说:汪汪!")

    def show_breed(self):
        print(f"{self.name} 的品种是 {self.breed}")

my_dog = Dog("Buddy", "拉布拉多")
my_dog.make_sound()   # 输出: Buddy 说:汪汪!
my_dog.show_breed()   # 输出: Buddy 的品种是 拉布拉多

在这个例子中:

  • super().__init__(name) 调用父类的 __init__ 方法,初始化 name 属性。
  • 子类添加了 breed 属性和 show_breed 方法,扩展了功能。

4. 什么是多态?

多态(Polymorphism) 允许不同类的实例以统一的方式调用相同名称的方法,但表现出不同的行为。多态通常通过方法重写实现,子类提供与父类同名方法的自定义版本。

以下是一个展示多态的示例:

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

    def make_sound(self):
        print(f"{self.name} 发出声音")

class Dog(Animal):
    def make_sound(self):
        print(f"{self.name} 说:汪汪!")

class Cat(Animal):
    def make_sound(self):
        print(f"{self.name} 说:喵喵!")

animals = [Dog("Buddy"), Cat("Whiskers")]
for animal in animals:
    animal.make_sound()  # 输出: Buddy 说:汪汪!  Whiskers 说:喵喵!

在这个例子中:

  • DogCat 都继承了 Animal,并重写了 make_sound 方法。
  • 通过循环调用 make_sound,不同类的实例表现出不同的行为,体现了多态。

5. 方法重写与方法扩展

子类可以重写父类方法(完全替换实现)或扩展父类方法(保留父类行为并添加新功能)。

以下是方法扩展的示例:

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

    def make_sound(self):
        print(f"{self.name} 发出声音")

class Dog(Animal):
    def make_sound(self):
        super().make_sound()  # 调用父类方法
        print(f"{self.name} 说:汪汪!")

my_dog = Dog("Buddy")
my_dog.make_sound()  # 输出: Buddy 发出声音  Buddy 说:汪汪!

在这个例子中:

  • Dogmake_sound 方法先调用父类的 make_sound,然后添加自己的实现。
  • 这种方式适合在保留父类功能的基础上扩展行为。

6. 多重继承

Python支持多重继承,即一个类可以同时继承多个父类。子类会继承所有父类的属性和方法,但需要注意方法解析顺序(MRO)。

以下是一个多重继承的示例:

class Flyer:
    def fly(self):
        print("我在飞!")

class Swimmer:
    def swim(self):
        print("我在游!")

class Duck(Flyer, Swimmer):  # 多重继承
    def quack(self):
        print("嘎嘎!")

my_duck = Duck()
my_duck.fly()    # 输出: 我在飞!
my_duck.swim()   # 输出: 我在游!
my_duck.quack()  # 输出: 嘎嘎!

在这个例子中:

  • Duck 继承了 FlyerSwimmer,因此拥有 flyswim 方法。
  • 多重继承需谨慎使用,避免方法冲突或复杂性增加。
  • 使用 Duck.__mro__ 可以查看方法解析顺序。

7. 访问限制与继承

在继承中,父类的访问限制会影响子类的访问:

  • 公开成员:子类和外部都可以直接访问。
  • 受保护成员_ 前缀):子类可以访问,但不建议外部访问。
  • 私有成员__ 前缀):子类无法直接访问,需通过父类的公开方法访问。

以下是访问限制的示例:

class Animal:
    def __init__(self, name):
        self._name = name        # 受保护
        self.__secret = "秘密"    # 私有

    def get_secret(self):        # 公开方法访问私有属性
        return self.__secret

class Dog(Animal):
    def show_info(self):
        print(f"名字: {self._name}")
        print(f"秘密: {self.get_secret()}")

my_dog = Dog("Buddy")
my_dog.show_info()      # 输出: 名字: Buddy  秘密: 秘密
print(my_dog.__secret)  # 错误: AttributeError

在这个例子中:

  • 子类 Dog 可以访问受保护属性 _name
  • 私有属性 __secret 只能通过父类的 get_secret 方法访问。

8. 注意事项

  • 避免过度继承:深层继承可能导致代码复杂,优先考虑组合(将对象作为属性)而非继承。
  • 方法解析顺序(MRO):在多重继承中,Python使用C3线性化算法确定方法调用顺序,查看 __mro__ 可了解顺序。
  • 多态的灵活性:多态适合处理不同类型的对象,但需确保接口一致。
  • 私有成员的限制:私有成员在继承中需通过 getter 方法访问,以保持封装。

总结

继承和多态是Python面向对象编程的强大工具:

  • 继承允许子类重用和扩展父类的代码,使用 super() 调用父类方法。
  • 多态通过方法重写实现不同类对象的统一调用。
  • 多重继承提供灵活性,但需注意方法冲突。
  • 结合访问限制,继承可以更安全地组织代码。

下一节我们将探讨实例属性和类属性,继续深入OOP!