# 面向对象编程 Python 的 OOP 有其独特之处,理解这些特性能帮助你写出更优雅的代码。 ## 类与实例 ### 类属性 vs 实例属性 ```python class Dog: species = "Canis familiaris" # 类属性,所有实例共享 def __init__(self, name): self.name = name # 实例属性,每个实例独立 buddy = Dog("Buddy") miles = Dog("Miles") print(buddy.species) # Canis familiaris print(miles.species) # Canis familiaris # ⚠️ 易错点:通过实例修改类属性 buddy.species = "Canis lupus" # 创建实例属性,遮蔽类属性 print(buddy.species) # Canis lupus print(miles.species) # Canis familiaris - 不受影响 print(Dog.species) # Canis familiaris - 类属性未变 # 正确修改类属性 Dog.species = "Modified" print(miles.species) # Modified ``` ### 可变类属性陷阱 ```python # ❌ 危险:可变类属性被所有实例共享 class BadStudent: grades = [] # 所有实例共享同一个列表! def add_grade(self, grade): self.grades.append(grade) s1 = BadStudent() s2 = BadStudent() s1.add_grade(90) print(s2.grades) # [90] - s2 也有了 s1 的成绩! # ✅ 正确:在 __init__ 中初始化可变属性 class GoodStudent: def __init__(self): self.grades = [] # 每个实例独立的列表 def add_grade(self, grade): self.grades.append(grade) ``` ## 继承与组合 ### 方法解析顺序(MRO) ```python class A: def method(self): print("A") class B(A): def method(self): print("B") super().method() class C(A): def method(self): print("C") super().method() class D(B, C): def method(self): print("D") super().method() d = D() d.method() # D # B # C # A # 查看 MRO print(D.__mro__) # (, , , , ) ``` :::{tip} 理解 MRO 对于正确使用 `super()` 至关重要。Python 使用 C3 线性化算法确保每个类只被调用一次。 ::: ### 组合优于继承 ```python # ❌ 过度使用继承 class Car(Engine, Wheels, Seats): # 多重继承复杂度高 pass # ✅ 使用组合 class Engine: def start(self): return "Engine started" class Car: def __init__(self): self.engine = Engine() # 组合 def start(self): return self.engine.start() # 更灵活:可以在运行时替换组件 class ElectricEngine: def start(self): return "Electric engine started silently" electric_car = Car() electric_car.engine = ElectricEngine() print(electric_car.start()) # Electric engine started silently ``` ## 属性(Property) ### 使用 @property 实现访问控制 ```python class Temperature: def __init__(self, celsius=0): self._celsius = celsius # 内部存储 @property def celsius(self): """获取摄氏温度""" return self._celsius @celsius.setter def celsius(self, value): """设置摄氏温度,带验证""" if value < -273.15: raise ValueError("Temperature below absolute zero!") self._celsius = value @property def fahrenheit(self): """计算属性:华氏温度""" return self._celsius * 9/5 + 32 @fahrenheit.setter def fahrenheit(self, value): self.celsius = (value - 32) * 5/9 temp = Temperature(25) print(temp.celsius) # 25 print(temp.fahrenheit) # 77.0 temp.fahrenheit = 100 print(temp.celsius) # 37.77... # temp.celsius = -300 # ValueError ``` ### 只读属性 ```python class Circle: def __init__(self, radius): self._radius = radius @property def radius(self): return self._radius @property def area(self): """只读计算属性""" import math return math.pi * self._radius ** 2 @property def diameter(self): return self._radius * 2 c = Circle(5) print(c.area) # 78.53... # c.area = 100 # AttributeError: can't set attribute ``` ## 描述符 描述符是 property、classmethod、staticmethod 的底层机制。 ```python class Validator: """数据验证描述符""" def __init__(self, min_value=None, max_value=None): self.min_value = min_value self.max_value = max_value def __set_name__(self, owner, name): self.name = name self.private_name = f'_{name}' def __get__(self, obj, objtype=None): if obj is None: return self return getattr(obj, self.private_name, None) def __set__(self, obj, value): if self.min_value is not None and value < self.min_value: raise ValueError(f"{self.name} must be >= {self.min_value}") if self.max_value is not None and value > self.max_value: raise ValueError(f"{self.name} must be <= {self.max_value}") setattr(obj, self.private_name, value) class Product: price = Validator(min_value=0) quantity = Validator(min_value=0, max_value=1000) def __init__(self, name, price, quantity): self.name = name self.price = price self.quantity = quantity product = Product("Widget", 9.99, 100) # product.price = -1 # ValueError: price must be >= 0 # product.quantity = 2000 # ValueError: quantity must be <= 1000 ``` ## 抽象基类 ```python from abc import ABC, abstractmethod class Shape(ABC): """形状抽象基类""" @abstractmethod def area(self): """计算面积""" pass @abstractmethod def perimeter(self): """计算周长""" pass def describe(self): """具体方法""" return f"Area: {self.area()}, Perimeter: {self.perimeter()}" # shape = Shape() # TypeError: Can't instantiate abstract class 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) rect = Rectangle(3, 4) print(rect.describe()) # Area: 12, Perimeter: 14 ``` ## 数据类(Python 3.7+) ```python from dataclasses import dataclass, field from typing import List @dataclass class Point: x: float y: float def distance_from_origin(self): return (self.x ** 2 + self.y ** 2) ** 0.5 # 自动生成 __init__, __repr__, __eq__ p1 = Point(3, 4) p2 = Point(3, 4) print(p1) # Point(x=3, y=4) print(p1 == p2) # True @dataclass class Student: name: str grades: List[int] = field(default_factory=list) # 可变默认值 gpa: float = field(init=False) # 不在 __init__ 中 def __post_init__(self): if self.grades: self.gpa = sum(self.grades) / len(self.grades) else: self.gpa = 0.0 @dataclass(frozen=True) # 不可变 class FrozenPoint: x: float y: float fp = FrozenPoint(1, 2) # fp.x = 3 # FrozenError ``` ## 元类 元类是"类的类",用于控制类的创建过程。 ```python class SingletonMeta(type): """单例元类""" _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] class Database(metaclass=SingletonMeta): def __init__(self): self.connection = "Connected" db1 = Database() db2 = Database() print(db1 is db2) # True # 更简单的单例实现(推荐) class SimpleSingleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance ``` ### 使用 `__init_subclass__` 替代简单元类 ```python class PluginBase: """插件注册基类(Python 3.6+)""" _plugins = {} def __init_subclass__(cls, plugin_name=None, **kwargs): super().__init_subclass__(**kwargs) if plugin_name: cls._plugins[plugin_name] = cls @classmethod def get_plugin(cls, name): return cls._plugins.get(name) class JSONPlugin(PluginBase, plugin_name="json"): def process(self, data): return f"JSON: {data}" class XMLPlugin(PluginBase, plugin_name="xml"): def process(self, data): return f"XML: {data}" print(PluginBase._plugins) # {'json': , 'xml': } plugin = PluginBase.get_plugin("json")() print(plugin.process("data")) # JSON: data ``` ## 最佳实践 ::::{grid} 1 :gutter: 2 :::{grid-item-card} 设计原则 1. **优先使用组合而非继承** 2. **保持类的职责单一** 3. **使用数据类减少样板代码** 4. **避免深层继承层次** ::: :::{grid-item-card} 访问控制 1. **使用 `_` 前缀表示内部属性**(约定,非强制) 2. **使用 `@property` 实现受控访问** 3. **避免使用 `__` 双下划线**(除非确实需要名称改编) ::: :::{grid-item-card} 常见错误 1. **可变类属性被所有实例共享** 2. **忘记调用 `super().__init__()`** 3. **多重继承时的钻石问题** 4. **混淆类方法和静态方法** ::: ::::