11.Python 面向对象三大特性详解:封装、继承、多态与多继承、魔术方法及抽象类

摘要:本文系统讲解了 Python 面向对象的三大特性——封装、继承(重点涵盖多继承与 MRO)和多态,同时介绍了常用的魔术方法、魔术属性以及如何使用 abc 模块定义抽象类,帮助开发者深入理解 Python 面向对象编程的核心机制与最佳实践。

目录

1. 封装:数据与行为的捆绑

1.1 私有属性和方法

2. 继承:复用与扩展

2.1 单继承

2.2 多继承

2.3 方法解析顺序(MRO)

3. 多态:统一的接口,不同的实现

4. 魔术属性和魔术方法

4.1 常用魔术方法

4.2 常用魔术属性

5. 抽象类:定义接口规范


1. 封装:数据与行为的捆绑

封装是面向对象编程的核心思想之一,它将数据(属性)和操作数据的方法(函数)绑定在一起,形成一个独立的单元——类。在 Python 中,封装主要通过命名约定和访问控制来实现。

1.1 私有属性和方法

Python 没有严格的访问修饰符(如 Java 的 private),但社区约定以单下划线_name表示"受保护的"成员,建议外部不要直接访问;双下划线__name会触发名称改写机制,使得外部难以直接访问,从而实现更严格的私有化。

class BankAccount: def __init__(self, owner, balance=0): self.owner = owner # 公开属性 self._balance = balance # 受保护属性,不建议外部直接修改 self.__password = "1234" # 私有属性,名称被改写为 _BankAccount__password def deposit(self, amount): if amount > 0: self._balance += amount return self._balance def get_balance(self): return self._balance account = BankAccount("Alice", 1000) print(account.get_balance()) # 1000 print(account.__password) # AttributeError print(account._BankAccount__password) # 仍可访问,但不推荐

封装的好处在于隐藏实现细节,只暴露必要的接口,提高代码的安全性和可维护性。

2. 继承:复用与扩展

继承允许我们基于已有的类(父类/基类)创建新的类(子类/派生类),子类自动获得父类的属性和方法,并可以添加或覆盖自己的行为。

2.1 单继承

class Animal: def __init__(self, name): self.name = name def speak(self): return f"{self.name} makes a sound." class Dog(Animal): def speak(self): # 方法重写 return f"{self.name} barks." dog = Dog("Buddy") print(dog.speak()) # Buddy barks.

2.2 多继承

Python 支持多继承,即一个类可以同时继承多个父类。这使得代码复用更加灵活,但也带来了方法解析顺序的复杂性。

class Flyable: def fly(self): return "I can fly!" class Swimmable: def swim(self): return "I can swim!" class Duck(Animal, Flyable, Swimmable): def speak(self): return f"{self.name} quacks." duck = Duck("Donald") print(duck.speak()) # Donald quacks. (来自 Animal,重写后) print(duck.fly()) # I can fly! (来自 Flyable) print(duck.swim()) # I can swim! (来自 Swimmable)

2.3 方法解析顺序(MRO)

当多个父类中存在同名方法时,Python 使用 C3 线性化算法确定方法的搜索顺序。可以通过__mro__属性或mro()方法查看继承链。

class A: def method(self): return "A" class B(A): def method(self): return "B" class C(A): def method(self): return "C" class D(B, C): pass print(D().method()) # "B",因为 MRO 为 D -> B -> C -> A print(D.mro)

多继承极大地增强了代码组合能力,常与 Mixin 模式结合使用。Mixin 是一种只提供特定功能的类,通常不单独实例化。

class LoggerMixin: def log(self, message): print(f"[LOG] {message}") class DataProcessor(LoggerMixin): def process(self, data): self.log("Processing data...") # 处理逻辑 return data processor = DataProcessor() processor.process("sample")

3. 多态:统一的接口,不同的实现

多态指同一个接口可以根据对象类型的不同而表现出不同的行为。在 Python 中,多态主要依赖鸭子类型:只要对象实现了所需的方法,就可以作为参数传递,而不强制要求继承自特定基类。

class Cat(Animal): def speak(self): return f"{self.name} meows." class Bird(Animal): def speak(self): return f"{self.name} chirps." def animal_sound(animal): print(animal.speak()) animal_sound(Dog("Rex")) # Rex barks. animal_sound(Cat("Whiskers")) # Whiskers meows. animal_sound(Bird("Tweety")) # Tweety chirps.

多态让代码更加灵活、可扩展,符合开闭原则。

4. 魔术属性和魔术方法

魔术方法(Magic Methods)是 Python 中以双下划线开头和结尾的特殊方法,它们会在特定操作发生时被自动调用。魔术属性则是 Python 内置的特殊属性,用于访问类的元信息。

4.1 常用魔术方法

  • __init__:构造方法,对象初始化时调用。
  • __str__:定义对象被str()print()时的字符串表示。
  • __repr__:定义对象的"官方"字符串表示,通常用于调试。
  • __len__:支持len()函数。
  • __getitem__/__setitem__:使对象支持下标访问。
  • __call__:使实例像函数一样可调用。
  • __add____mul__等:运算符重载。
class Vector: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return f"Vector({self.x}, {self.y})" def add(self, other): return Vector(self.x + other.x, self.y + other.y) def len(self): return 2 v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) # Vector(4, 6) print(len(v1)) # 2

4.2 常用魔术属性

  • __dict__:返回对象的属性字典。
  • __class__:返回对象所属的类。
  • __doc__:返回类的文档字符串。
  • __name__:返回类名(字符串)。
  • __module__:返回类定义所在的模块名。
class Person: """人类模型""" def __init__(self, name, age): self.name = name self.age = age p = Person("Alice", 30) print(p.dict) # {'name': 'Alice', 'age': 30} print(p.class) # <class 'main.Person'> print(Person.doc) # 人类模型 print(Person.name) # Person

5. 抽象类:定义接口规范

抽象类是一种不能直接实例化的类,它定义了一组必须由子类实现的抽象方法。Python 通过abc模块提供抽象基类的支持。抽象类常与多态结合,强制子类实现特定接口。

from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass @abstractmethod def perimeter(self): pass class Circle(Shape): def init(self, radius): self.radius = radius def area(self): return 3.14159 * self.radius ** 2 def perimeter(self): return 2 * 3.14159 * self.radius class Rectangle(Shape): def init(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height def perimeter(self): return 2 * (self.width + self.height) shapes = [Circle(5), Rectangle(4, 6)] for s in shapes: print(f"{s.class.name} area: {s.area()}") Circle area: 78.53975 Rectangle area: 24

抽象类确保了所有子类都遵循统一的接口约定,提高了代码的健壮性和可读性。如果子类未实现所有抽象方法,Python 会在实例化时抛出TypeError