面对对象编程

Python基础 2026-04-20 10
预计阅读时间:39 分钟

Python 面向对象编程深度解析

一、面向对象的核心思想

面向对象编程(OOP)不是简单的语法糖,而是一种组织代码的思维方式。它通过将数据和操作数据的方法封装在一起,模拟现实世界的事物和它们之间的关系。

1.1 为什么需要面向对象?

# 面向过程的方式
def calculate_circle_area(radius):
    return 3.14159 * radius * radius

def calculate_circle_perimeter(radius):
    return 2 * 3.14159 * radius

radius1 = 5
radius2 = 10
area1 = calculate_circle_area(radius1)
perimeter1 = calculate_circle_perimeter(radius1)

# 面向对象的方式
class Circle:
    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

circle1 = Circle(5)
circle2 = Circle(10)
print(f"圆1面积: {circle1.area()}, 周长: {circle1.perimeter()}")
print(f"圆2面积: {circle2.area()}, 周长: {circle2.perimeter()}")

# OOP的优势:
# 1. 数据和操作绑定在一起
# 2. 代码更容易理解和维护
# 3. 便于扩展和复用

1.2 三大核心特性

# 面向对象的三大支柱:
# 1. 封装 (Encapsulation) - 隐藏内部实现
# 2. 继承 (Inheritance) - 复用和扩展已有代码
# 3. 多态 (Polymorphism) - 统一接口,不同实现

class BankAccount:
    """封装示例:银行账户"""

    def __init__(self, owner, initial_balance=0):
        self.owner = owner
        self.__balance = initial_balance  # 私有属性(名称改编)
        self._transaction_history = []    # 受保护属性(约定)

    def deposit(self, amount):
        """存款(公有接口)"""
        if amount <= 0:
            raise ValueError("存款金额必须大于0")
        self.__balance += amount
        self._add_transaction(f"存款: +{amount}")

    def withdraw(self, amount):
        """取款(公有接口)"""
        if amount <= 0:
            raise ValueError("取款金额必须大于0")
        if amount > self.__balance:
            raise ValueError("余额不足")
        self.__balance -= amount
        self._add_transaction(f"取款: -{amount}")

    def get_balance(self):
        """查询余额(受控访问)"""
        return self.__balance

    def _add_transaction(self, description):
        """添加交易记录(内部使用)"""
        from datetime import datetime
        self._transaction_history.append({
            'time': datetime.now(),
            'description': description,
            'balance': self.__balance
        })

    def get_history(self):
        """获取交易历史(只读副本)"""
        return self._transaction_history.copy()

# 使用
account = BankAccount("Alice", 1000)
account.deposit(500)
account.withdraw(200)
print(f"余额: {account.get_balance()}")
# print(account.__balance)  # AttributeError,无法直接访问
print(f"交易记录: {len(account.get_history())} 条")

二、类的定义与实例化

2.1 类的基本结构

class Person:
    """人类 - 展示类的完整结构"""

    # 类属性(所有实例共享)
    species = "Homo Sapiens"
    count = 0

    def __init__(self, name, age):
        # 实例属性(每个实例独立)
        self.name = name
        self.age = age
        self._created_at = self._get_current_time()

        # 修改类属性
        Person.count += 1

    # 实例方法(最常用)
    def introduce(self):
        return f"我叫 {self.name},今年 {self.age} 岁"

    # 类方法(操作类属性)
    @classmethod
    def get_count(cls):
        return f"已创建 {cls.count} 个人"

    @classmethod
    def create_baby(cls, name):
        """工厂方法:创建婴儿"""
        return cls(name, 0)

    # 静态方法(工具函数)
    @staticmethod
    def _get_current_time():
        from datetime import datetime
        return datetime.now()

    @staticmethod
    def is_adult(age):
        return age >= 18

    # 特殊方法(魔术方法)
    def __str__(self):
        return f"Person({self.name}, {self.age})"

    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age})"

    def __eq__(self, other):
        if not isinstance(other, Person):
            return False
        return self.name == other.name and self.age == other.age

    def __lt__(self, other):
        """小于比较(用于排序)"""
        return self.age < other.age

# 使用示例
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
baby = Person.create_baby("Charlie")

print(person1.introduce())
print(Person.get_count())
print(f"Alice 是成年人吗? {Person.is_adult(person1.age)}")

# 自动调用特殊方法
print(str(person1))      # __str__
print(repr(person1))     # __repr__
print(person1 == person2)  # __eq__

people = [person2, person1]
print(sorted(people))  # __lt__ 实现排序

2.2 属性访问控制

class Temperature:
    """展示 Python 的属性访问控制"""

    def __init__(self, celsius=0):
        self._celsius = celsius  # 受保护属性
        self.__kelvin_offset = 273.15  # 私有属性

    # 使用 property 装饰器
    @property
    def celsius(self):
        """获取摄氏度"""
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        """设置摄氏度(带验证)"""
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        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

    @property
    def kelvin(self):
        """开尔文(只读属性)"""
        return self._celsius + self.__kelvin_offset

    # 使用 property 函数(旧式方法)
    def get_kelvin_offset(self):
        return self.__kelvin_offset

    kelvin_offset = property(get_kelvin_offset)

    # 属性删除器
    @celsius.deleter
    def celsius(self):
        del self._celsius

# 使用
temp = Temperature(25)
print(f"摄氏度: {temp.celsius}°C")
print(f"华氏度: {temp.fahrenheit}°F")
print(f"开尔文: {temp.kelvin}K")

temp.celsius = 30
print(f"新的华氏度: {temp.fahrenheit}°F")

temp.fahrenheit = 100
print(f"对应的摄氏度: {temp.celsius}°C")

# 访问私有属性(名称改编)
# print(temp.__kelvin_offset)  # AttributeError
print(temp._Temperature__kelvin_offset)  # 可以访问,但不推荐

2.3 类装饰器与元类初探

# 使用类装饰器增强类
def add_repr(cls):
    """为类添加 __repr__ 方法"""
    def __repr__(self):
        attrs = ', '.join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{cls.__name__}({attrs})"

    cls.__repr__ = __repr__
    return cls

def add_str(cls):
    """为类添加 __str__ 方法"""
    def __str__(self):
        return f"{cls.__name__} 实例"

    cls.__str__ = __str__
    return cls

@add_repr
@add_str
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(3, 4)
print(p)        # Point 实例
print(repr(p))  # Point(x=3, y=4)

# 使用 dataclass 简化类定义
from dataclasses import dataclass, field
from typing import List

@dataclass(order=True)
class Student:
    sort_index: int = field(init=False, repr=False)
    name: str
    age: int
    grades: List[float] = field(default_factory=list)

    def __post_init__(self):
        """初始化后处理"""
        self.sort_index = self.age

    def average_grade(self):
        if not self.grades:
            return 0
        return sum(self.grades) / len(self.grades)

student = Student("Alice", 20, [85, 90, 88])
print(student)
print(f"平均分: {student.average_grade():.1f}")

三、继承与多态

3.1 基础继承

class Animal:
    """动物基类"""

    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._energy = 100

    def eat(self, food):
        """吃食物恢复能量"""
        self._energy += food.energy
        return f"{self.name} 吃了 {food.name}"

    def sleep(self):
        """睡觉恢复能量"""
        self._energy = 100
        return f"{self.name} 睡了一觉,精力充沛"

    def make_sound(self):
        """发出声音(子类应该重写)"""
        raise NotImplementedError("子类必须实现 make_sound 方法")

    def get_status(self):
        return f"{self.name} (能量: {self._energy})"

class Food:
    """食物类"""
    def __init__(self, name, energy):
        self.name = name
        self.energy = energy

class Dog(Animal):
    """狗类 - 继承自 Animal"""

    def __init__(self, name, age, breed="混血"):
        # 调用父类初始化
        super().__init__(name, age)
        self.breed = breed
        self._tricks = []

    def make_sound(self):
        """重写父类方法"""
        return f"{self.name}: 汪汪!"

    def wag_tail(self):
        """狗特有的方法"""
        return f"{self.name} 摇尾巴"

    def learn_trick(self, trick):
        """学习新技能"""
        self._tricks.append(trick)
        return f"{self.name} 学会了 {trick}"

    def perform_tricks(self):
        """表演所有技能"""
        if not self._tricks:
            return f"{self.name} 还不会任何技能"
        tricks = ', '.join(self._tricks)
        return f"{self.name} 表演: {tricks}"

    def get_status(self):
        """扩展父类方法"""
        base_status = super().get_status()
        return f"{base_status}, 品种: {self.breed}"

class Cat(Animal):
    """猫类"""

    def __init__(self, name, age, color="橘色"):
        super().__init__(name, age)
        self.color = color
        self._mice_caught = 0

    def make_sound(self):
        return f"{self.name}: 喵喵~"

    def catch_mouse(self):
        """猫特有的方法"""
        self._mice_caught += 1
        self._energy -= 10
        return f"{self.name} 抓到了一只老鼠!总共抓到 {self._mice_caught} 只"

    def purr(self):
        return f"{self.name} 发出咕噜声"

# 使用
dog = Dog("旺财", 3, "金毛")
cat = Cat("咪咪", 2)

print(dog.make_sound())
print(cat.make_sound())

food = Food("狗粮", 20)
print(dog.eat(food))
print(dog.learn_trick("坐下"))
print(dog.learn_trick("握手"))
print(dog.perform_tricks())

print(cat.catch_mouse())
print(cat.purr())

# 多态:统一接口,不同实现
animals = [dog, cat]
for animal in animals:
    print(f"{animal.name}: {animal.make_sound()}")
    print(f"  状态: {animal.get_status()}")

3.2 多重继承与 MRO

class Flyable:
    """会飞的"""

    def fly(self):
        return f"{self.__class__.__name__} 在飞行"

    def move(self):
        return self.fly()

class Swimmable:
    """会游泳的"""

    def swim(self):
        return f"{self.__class__.__name__} 在游泳"

    def move(self):
        return self.swim()

class Walkable:
    """会行走的"""

    def walk(self):
        return f"{self.__class__.__name__} 在行走"

    def move(self):
        return self.walk()

# 多重继承
class Duck(Walkable, Swimmable, Flyable):
    """鸭子 - 继承自多个父类"""

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

    def quack(self):
        return f"{self.name}: 嘎嘎!"

    # 重写 move 方法,结合多种能力
    def move(self):
        return f"{self.name} 可以走路、游泳和飞行"

class Penguin(Walkable, Swimmable):
    """企鹅 - 不会飞"""

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

    def move(self):
        return f"{self.name} 摇摇摆摆地走路,优雅地游泳"

# 查看方法解析顺序(MRO)
print("Duck MRO:", [cls.__name__ for cls in Duck.__mro__])
print("Penguin MRO:", [cls.__name__ for cls in Penguin.__mro__])

duck = Duck("唐老鸭")
penguin = Penguin("企鹅")

print(duck.quack())
print(duck.walk())
print(duck.swim())
print(duck.fly())
print(duck.move())

print(penguin.walk())
print(penguin.swim())
# print(penguin.fly())  # AttributeError,Penguin 没有 fly 方法

# 菱形继承问题
class A:
    def method(self):
        return "A.method"

    def call(self):
        return "A.call"

class B(A):
    def method(self):
        return "B.method"

    def call(self):
        return f"B.call -> {super().call()}"

class C(A):
    def method(self):
        return "C.method"

    def call(self):
        return f"C.call -> {super().call()}"

class D(B, C):
    def method(self):
        return f"D.method -> {super().method()}"

# MRO 确保每个父类只调用一次
print("D MRO:", [cls.__name__ for cls in D.__mro__])
d = D()
print(d.method())
print(d.call())  # 协作式多重继承

3.3 抽象基类

from abc import ABC, abstractmethod
import math

class Shape(ABC):
    """形状抽象基类"""

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

    @abstractmethod
    def area(self):
        """计算面积 - 子类必须实现"""
        pass

    @abstractmethod
    def perimeter(self):
        """计算周长 - 子类必须实现"""
        pass

    def describe(self):
        """具体方法(子类可选重写)"""
        return f"{self.name}: 面积={self.area():.2f}, 周长={self.perimeter():.2f}"

    @classmethod
    def __subclasshook__(cls, subclass):
        """自定义子类检查(鸭子类型)"""
        if cls is Shape:
            required_methods = ['area', 'perimeter']
            if all(hasattr(subclass, method) for method in required_methods):
                return True
        return NotImplemented

class Circle(Shape):
    """圆形"""

    def __init__(self, radius):
        super().__init__("圆形")
        self.radius = radius

    def area(self):
        return math.pi * self.radius ** 2

    def perimeter(self):
        return 2 * math.pi * self.radius

    def diameter(self):
        """圆形特有的方法"""
        return 2 * self.radius

class Rectangle(Shape):
    """矩形"""

    def __init__(self, width, height):
        super().__init__("矩形")
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

    @property
    def is_square(self):
        """是否为正方形"""
        return self.width == self.height

class Triangle(Shape):
    """三角形"""

    def __init__(self, a, b, c):
        super().__init__("三角形")
        self.a = a
        self.b = b
        self.c = c

        # 验证是否为有效三角形
        if not self._is_valid():
            raise ValueError("无效的三角形边长")

    def _is_valid(self):
        """检查是否为有效三角形"""
        return (self.a + self.b > self.c and 
                self.b + self.c > self.a and 
                self.c + self.a > self.b)

    def area(self):
        # 海伦公式
        s = self.perimeter() / 2
        return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))

    def perimeter(self):
        return self.a + self.b + self.c

# 使用抽象基类
shapes = [
    Circle(5),
    Rectangle(4, 6),
    Triangle(3, 4, 5)
]

for shape in shapes:
    print(shape.describe())
    if isinstance(shape, Circle):
        print(f"  直径: {shape.diameter():.2f}")
    elif isinstance(shape, Rectangle):
        print(f"  是正方形吗? {shape.is_square}")

# 鸭子类型:只要实现了 area 和 perimeter,就可以被识别为 Shape
class House:
    """一个实现了面积和周长的类,但不是 Shape 的子类"""

    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * (self.length + self.width)

house = House(10, 8)
print(f"House 是 Shape 的子类吗? {issubclass(House, Shape)}")  # True(因为 __subclasshook__)
print(f"房子的 {house.area()} 平方米")

四、高级面向对象特性

4.1 描述符(Descriptor)

class Validator:
    """描述符基类"""

    def __init__(self, name=None):
        self.name = name

    def __set_name__(self, owner, name):
        """Python 3.6+ 自动调用,设置属性名"""
        self.name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name)

    def __set__(self, instance, value):
        self.validate(value)
        instance.__dict__[self.name] = value

    def validate(self, value):
        """子类应该重写此方法"""
        pass

class PositiveNumber(Validator):
    """正数验证器"""

    def validate(self, value):
        if value <= 0:
            raise ValueError(f"{self.name} 必须是正数")
        return value

class StringLength(Validator):
    """字符串长度验证器"""

    def __init__(self, min_len=1, max_len=None):
        super().__init__()
        self.min_len = min_len
        self.max_len = max_len

    def validate(self, value):
        if not isinstance(value, str):
            raise TypeError(f"{self.name} 必须是字符串")
        if len(value) < self.min_len:
            raise ValueError(f"{self.name} 长度至少为 {self.min_len}")
        if self.max_len and len(value) > self.max_len:
            raise ValueError(f"{self.name} 长度最多为 {self.max_len}")
        return value

class Email(Validator):
    """邮箱验证器"""

    def validate(self, value):
        if not isinstance(value, str):
            raise TypeError("邮箱必须是字符串")
        if '@' not in value or '.' not in value:
            raise ValueError(f"无效的邮箱格式: {value}")
        return value

class Typed(Validator):
    """类型验证器"""

    def __init__(self, expected_type):
        super().__init__()
        self.expected_type = expected_type

    def validate(self, value):
        if not isinstance(value, self.expected_type):
            raise TypeError(f"{self.name} 必须是 {self.expected_type.__name__} 类型")
        return value

# 使用描述符
class Product:
    """产品类 - 使用描述符进行验证"""

    name = StringLength(min_len=2, max_len=50)
    price = PositiveNumber()
    quantity = PositiveNumber()
    description = StringLength(min_len=10)

    def __init__(self, name, price, quantity, description=""):
        self.name = name
        self.price = price
        self.quantity = quantity
        self.description = description or f"{name} 的产品描述,非常优质"

    @property
    def total_value(self):
        return self.price * self.quantity

    def __str__(self):
        return f"{self.name} (价格: ¥{self.price}, 库存: {self.quantity})"

class User:
    """用户类"""

    username = StringLength(min_len=3, max_len=20)
    email = Email()
    age = PositiveNumber()

    def __init__(self, username, email, age):
        self.username = username
        self.email = email
        self.age = age

# 测试
try:
    product = Product("笔记本电脑", 5999, 10, "高性能笔记本电脑,适合办公和游戏")
    print(product)
    print(f"总价值: ¥{product.total_value}")

    user = User("alice", "alice@example.com", 25)
    print(f"用户: {user.username}, 邮箱: {user.email}")

    # 触发验证错误
    product.price = -100  # ValueError
except (ValueError, TypeError) as e:
    print(f"验证错误: {e}")

4.2 元类(Metaclass)

# 元类是类的类,控制类的创建过程

# 1. 使用 type 动态创建类
def say_hello(self):
    return f"Hello from {self.name}"

# 动态创建类
DynamicClass = type('DynamicClass', (object,), {
    'name': 'Dynamic',
    'say_hello': say_hello,
    '__str__': lambda self: f"DynamicClass({self.name})"
})

obj = DynamicClass()
print(obj.say_hello())

# 2. 自定义元类
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, host='localhost', port=3306):
        self.host = host
        self.port = port
        self.connected = False
        print(f"初始化数据库连接: {host}:{port}")

    def connect(self):
        self.connected = True
        return f"已连接到 {self.host}:{self.port}"

    def query(self, sql):
        if not self.connected:
            self.connect()
        return f"执行查询: {sql}"

# 测试单例
db1 = Database('db1.example.com', 3306)
db2 = Database('db2.example.com', 5432)
print(db1 is db2)  # True
print(db1.host)    # db1.example.com(第一次初始化的参数)

# 3. 验证类的元类
class ValidateFieldsMeta(type):
    """验证类属性的元类"""

    def __new__(mcs, name, bases, namespace):
        # 检查是否有 required_fields 属性
        if 'required_fields' in namespace:
            required = namespace['required_fields']
            for field in required:
                if field not in namespace:
                    raise TypeError(f"类 {name} 缺少必需字段: {field}")

        # 自动添加创建时间戳
        from datetime import datetime
        namespace['created_at'] = datetime.now()

        return super().__new__(mcs, name, bases, namespace)

class APIModel(metaclass=ValidateFieldsMeta):
    """API 模型基类"""

    required_fields = ['table_name']
    table_name = 'default_table'

    @classmethod
    def get_table_name(cls):
        return cls.table_name

# 正常定义
class UserModel(APIModel):
    table_name = 'users'
    fields = ['id', 'name', 'email']

print(f"UserModel 表名: {UserModel.get_table_name()}")
print(f"创建时间: {UserModel.created_at}")

# 错误定义
# class InvalidModel(APIModel):
#     pass  # TypeError: 类 InvalidModel 缺少必需字段: table_name

# 4. 自动注册的元类
class AutoRegisterMeta(type):
    """自动注册子类的元类"""

    registry = {}

    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)

        # 只注册非抽象类
        if not namespace.get('abstract', False):
            mcs.registry[name.lower()] = cls

        return cls

    @classmethod
    def get_class(mcs, name):
        """根据名称获取类"""
        return mcs.registry.get(name.lower())

class Plugin(metaclass=AutoRegisterMeta):
    """插件基类"""

    abstract = True  # 抽象类,不注册

    def execute(self):
        raise NotImplementedError

class ImagePlugin(Plugin):
    """图片处理插件"""

    def execute(self):
        return "处理图片"

class VideoPlugin(Plugin):
    """视频处理插件"""

    def execute(self):
        return "处理视频"

class AudioPlugin(Plugin):
    """音频处理插件"""

    def execute(self):
        return "处理音频"

# 使用自动注册
print("已注册的插件:", list(AutoRegisterMeta.registry.keys()))

# 根据名称动态创建实例
plugin_name = 'imageplugin'
plugin_class = AutoRegisterMeta.get_class(plugin_name)
if plugin_class:
    plugin = plugin_class()
    print(plugin.execute())

4.3 混入类(Mixin)

class SerializerMixin:
    """序列化混入"""

    def to_dict(self):
        """转换为字典"""
        result = {}
        for key, value in self.__dict__.items():
            # 跳过私有属性
            if key.startswith('_'):
                continue
            # 处理嵌套对象
            if hasattr(value, 'to_dict'):
                result[key] = value.to_dict()
            elif isinstance(value, (list, tuple)):
                result[key] = [
                    item.to_dict() if hasattr(item, 'to_dict') else item
                    for item in value
                ]
            else:
                result[key] = value
        return result

    def to_json(self):
        """转换为 JSON"""
        import json
        return json.dumps(self.to_dict(), ensure_ascii=False, default=str)

class TimestampMixin:
    """时间戳混入"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        from datetime import datetime
        self.created_at = datetime.now()
        self.updated_at = datetime.now()

    def update_timestamp(self):
        from datetime import datetime
        self.updated_at = datetime.now()

class LoggingMixin:
    """日志混入"""

    def log(self, message, level='INFO'):
        from datetime import datetime
        timestamp = datetime.now().isoformat()
        print(f"[{timestamp}] [{level}] {self.__class__.__name__}: {message}")

class ValidatableMixin:
    """验证混入"""

    def validate(self):
        """验证对象,子类应定义 _validate 方法"""
        if hasattr(self, '_validate'):
            return self._validate()
        return True

    def is_valid(self):
        try:
            return self.validate()
        except Exception:
            return False

# 组合使用多个混入
class BlogPost(SerializerMixin, TimestampMixin, LoggingMixin, ValidatableMixin):
    """博客文章 - 组合多个混入"""

    def __init__(self, title, content, author):
        # 注意:需要调用所有父类的 __init__
        super().__init__()
        self.title = title
        self.content = content
        self.author = author
        self.comments = []
        self.published = False

        self.log(f"创建文章: {title}")

    def publish(self):
        self.published = True
        self.update_timestamp()
        self.log(f"发布文章: {self.title}")

    def add_comment(self, comment):
        self.comments.append(comment)
        self.update_timestamp()
        self.log(f"添加评论: {comment.author}")

    def _validate(self):
        """自定义验证逻辑"""
        if not self.title:
            raise ValueError("标题不能为空")
        if len(self.title) > 200:
            raise ValueError("标题不能超过200字符")
        if not self.content:
            raise ValueError("内容不能为空")
        return True

class Comment(SerializerMixin, TimestampMixin):
    """评论类"""

    def __init__(self, author, text):
        super().__init__()
        self.author = author
        self.text = text

# 使用
post = BlogPost("Python 混入类", "混入是一种优雅的代码复用方式...", "Alice")
post.publish()

comment1 = Comment("Bob", "好文章!")
comment2 = Comment("Charlie", "学到了新知识")
post.add_comment(comment1)
post.add_comment(comment2)

# 序列化
print("\n文章字典:")
print(post.to_dict())
print("\n文章 JSON:")
print(post.to_json()[:200] + "...")

# 验证
print(f"\n文章有效吗? {post.is_valid()}")

五、设计模式实战

5.1 工厂模式

from abc import ABC, abstractmethod
from typing import Dict, Type

# 简单工厂
class Vehicle(ABC):
    """交通工具抽象类"""

    @abstractmethod
    def drive(self):
        pass

    @abstractmethod
    def get_capacity(self):
        pass

class Car(Vehicle):
    def __init__(self, model):
        self.model = model

    def drive(self):
        return f"驾驶汽车 {self.model}"

    def get_capacity(self):
        return 5

class Bike(Vehicle):
    def __init__(self, model):
        self.model = model

    def drive(self):
        return f"骑自行车 {self.model}"

    def get_capacity(self):
        return 1

class Bus(Vehicle):
    def __init__(self, model):
        self.model = model

    def drive(self):
        return f"驾驶公交车 {self.model}"

    def get_capacity(self):
        return 40

class VehicleFactory:
    """简单工厂"""

    @staticmethod
    def create_vehicle(vehicle_type: str, model: str) -> Vehicle:
        if vehicle_type == 'car':
            return Car(model)
        elif vehicle_type == 'bike':
            return Bike(model)
        elif vehicle_type == 'bus':
            return Bus(model)
        else:
            raise ValueError(f"未知的交通工具类型: {vehicle_type}")

# 工厂方法模式
class LogisticsApp(ABC):
    """物流应用(工厂方法)"""

    @abstractmethod
    def create_vehicle(self) -> Vehicle:
        """工厂方法"""
        pass

    def plan_delivery(self, distance):
        vehicle = self.create_vehicle()
        return f"使用 {vehicle.get_capacity()} 座位的交通工具,配送 {distance} 公里"

class UrbanLogistics(LogisticsApp):
    """城市物流"""

    def create_vehicle(self):
        return Bike("城市自行车")

class SuburbanLogistics(LogisticsApp):
    """郊区物流"""

    def create_vehicle(self):
        return Car("厢式货车")

class LongHaulLogistics(LogisticsApp):
    """长途物流"""

    def create_vehicle(self):
        return Bus("长途巴士")

# 抽象工厂模式
class VehiclePartsFactory(ABC):
    """车辆零件工厂(抽象工厂)"""

    @abstractmethod
    def create_engine(self):
        pass

    @abstractmethod
    def create_wheel(self):
        pass

class SportsCarPartsFactory(VehiclePartsFactory):
    """跑车零件工厂"""

    def create_engine(self):
        return "V8 发动机"

    def create_wheel(self):
        return "赛车轮胎"

class EconomyCarPartsFactory(VehiclePartsFactory):
    """经济型车零件工厂"""

    def create_engine(self):
        return "1.5L 发动机"

    def create_wheel(self):
        return "经济型轮胎"

class VehicleAssembler:
    """车辆装配器"""

    def __init__(self, parts_factory: VehiclePartsFactory):
        self.parts_factory = parts_factory

    def assemble(self):
        engine = self.parts_factory.create_engine()
        wheel = self.parts_factory.create_wheel()
        return f"装配完成:{engine} + {wheel}"

# 注册工厂(更灵活)
class RegisteredFactory:
    """注册工厂"""

    _registry: Dict[str, Type] = {}

    @classmethod
    def register(cls, name: str):
        """注册装饰器"""
        def decorator(target_class):
            cls._registry[name] = target_class
            return target_class
        return decorator

    @classmethod
    def create(cls, name: str, **kwargs):
        """创建实例"""
        if name not in cls._registry:
            raise ValueError(f"未注册的类型: {name}")
        return cls._registry[name](**kwargs)

@RegisteredFactory.register('electric_car')
class ElectricCar(Vehicle):
    def __init__(self, model, battery_capacity=75):
        self.model = model
        self.battery_capacity = battery_capacity

    def drive(self):
        return f"静音驾驶 {self.model} (电量: {self.battery_capacity}kWh)"

    def get_capacity(self):
        return 5

# 测试
print("=== 简单工厂 ===")
car = VehicleFactory.create_vehicle('car', 'Tesla Model 3')
print(car.drive())

print("\n=== 工厂方法 ===")
urban = UrbanLogistics()
print(urban.plan_delivery(5))

print("\n=== 抽象工厂 ===")
sports_assembler = VehicleAssembler(SportsCarPartsFactory())
print(sports_assembler.assemble())

print("\n=== 注册工厂 ===")
electric = RegisteredFactory.create('electric_car', model='Tesla Model S', battery_capacity=100)
print(electric.drive())

5.2 建造者模式

class Computer:
    """计算机产品"""

    def __init__(self):
        self.cpu = None
        self.ram = None
        self.storage = None
        self.gpu = None
        self.os = None

    def __str__(self):
        specs = []
        if self.cpu:
            specs.append(f"CPU: {self.cpu}")
        if self.ram:
            specs.append(f"RAM: {self.ram}")
        if self.storage:
            specs.append(f"存储: {self.storage}")
        if self.gpu:
            specs.append(f"GPU: {self.gpu}")
        if self.os:
            specs.append(f"系统: {self.os}")
        return "计算机配置:\n  " + "\n  ".join(specs)

class ComputerBuilder:
    """计算机建造者"""

    def __init__(self):
        self.computer = Computer()

    def set_cpu(self, cpu):
        self.computer.cpu = cpu
        return self

    def set_ram(self, ram):
        self.computer.ram = ram
        return self

    def set_storage(self, storage):
        self.computer.storage = storage
        return self

    def set_gpu(self, gpu):
        self.computer.gpu = gpu
        return self

    def set_os(self, os):
        self.computer.os = os
        return self

    def build(self):
        return self.computer

class GamingComputerDirector:
    """游戏电脑指导者"""

    @staticmethod
    def construct(builder: ComputerBuilder):
        return (builder
                .set_cpu("Intel i9-13900K")
                .set_ram("32GB DDR5")
                .set_storage("2TB NVMe SSD")
                .set_gpu("NVIDIA RTX 4090")
                .set_os("Windows 11 Pro")
                .build())

class OfficeComputerDirector:
    """办公电脑指导者"""

    @staticmethod
    def construct(builder: ComputerBuilder):
        return (builder
                .set_cpu("Intel i5-13400")
                .set_ram("16GB DDR4")
                .set_storage("512GB SSD")
                .set_gpu("集成显卡")
                .set_os("Windows 11 Home")
                .build())

# 使用建造者模式
builder = ComputerBuilder()

# 方式1:使用指导者
gaming_pc = GamingComputerDirector.construct(builder)
print("游戏电脑:")
print(gaming_pc)

# 方式2:自定义配置
builder = ComputerBuilder()
custom_pc = (builder
             .set_cpu("AMD Ryzen 7")
             .set_ram("32GB DDR5")
             .set_storage("1TB SSD + 2TB HDD")
             .set_os("Ubuntu 22.04")
             .build())

print("\n自定义电脑:")
print(custom_pc)

5.3 观察者模式

from abc import ABC, abstractmethod
from typing import List, Any

class Observer(ABC):
    """观察者接口"""

    @abstractmethod
    def update(self, subject: 'Subject', message: Any):
        pass

class Subject(ABC):
    """主题(被观察者)接口"""

    def __init__(self):
        self._observers: List[Observer] = []
        self._state = None

    def attach(self, observer: Observer):
        """添加观察者"""
        if observer not in self._observers:
            self._observers.append(observer)

    def detach(self, observer: Observer):
        """移除观察者"""
        self._observers.remove(observer)

    def notify(self, message: Any = None):
        """通知所有观察者"""
        for observer in self._observers:
            observer.update(self, message)

    @property
    def state(self):
        return self._state

    @state.setter
    def state(self, value):
        self._state = value
        self.notify(f"状态改变为: {value}")

# 具体实现
class NewsAgency(Subject):
    """新闻机构(被观察者)"""

    def __init__(self, name):
        super().__init__()
        self.name = name
        self.news = []

    def publish_news(self, title, content):
        """发布新闻"""
        news_item = {
            'title': title,
            'content': content,
            'agency': self.name
        }
        self.news.append(news_item)
        self.notify(news_item)
        return f"新闻已发布: {title}"

class EmailSubscriber(Observer):
    """邮件订阅者"""

    def __init__(self, email):
        self.email = email

    def update(self, subject, message):
        if isinstance(message, dict):
            print(f"[邮件] 发送到 {self.email}: {message['title']} - 来自 {message['agency']}")

class SMSSubscriber(Observer):
    """短信订阅者"""

    def __init__(self, phone):
        self.phone = phone

    def update(self, subject, message):
        if isinstance(message, dict):
            print(f"[短信] 发送到 {self.phone}: {message['title']}")

class LoggerSubscriber(Observer):
    """日志订阅者"""

    def update(self, subject, message):
        from datetime import datetime
        timestamp = datetime.now().isoformat()
        print(f"[日志 {timestamp}] 收到更新: {message}")

class DisplaySubscriber(Observer):
    """显示订阅者"""

    def __init__(self, display_name):
        self.display_name = display_name
        self.latest_news = None

    def update(self, subject, message):
        self.latest_news = message
        if isinstance(message, dict):
            print(f"[显示板 {self.display_name}] 最新新闻: {message['title']}")

# 使用观察者模式
print("=== 观察者模式示例 ===")

# 创建新闻机构
bbc = NewsAgency("BBC News")

# 创建订阅者
email_sub = EmailSubscriber("user@example.com")
sms_sub = SMSSubscriber("+1234567890")
logger_sub = LoggerSubscriber()
display = DisplaySubscriber("时代广场大屏幕")

# 订阅
bbc.attach(email_sub)
bbc.attach(sms_sub)
bbc.attach(logger_sub)
bbc.attach(display)

# 发布新闻
bbc.publish_news("Python 3.13 发布", "新版本带来了更好的性能...")
print()
bbc.publish_news("AI 技术突破", "新一代语言模型展现出惊人能力...")

# 取消订阅
bbc.detach(sms_sub)
print("\n取消短信订阅后:")
bbc.publish_news("天气更新", "今天天气晴朗...")

六、最佳实践与性能优化

6.1 类设计原则

"""
面向对象设计原则(SOLID):

1. 单一职责原则 (SRP) - 一个类只负责一件事
2. 开闭原则 (OCP) - 对扩展开放,对修改封闭
3. 里氏替换原则 (LSP) - 子类可以替换父类
4. 接口隔离原则 (ISP) - 接口应该小而专一
5. 依赖倒置原则 (DIP) - 依赖抽象而非具体
"""

# 违反单一职责
class BadUserManager:
    """违反 SRP:既管理用户又发送邮件"""

    def create_user(self, name, email):
        # 创建用户
        user = {'name': name, 'email': email}
        # 保存到数据库
        self.save_to_db(user)
        # 发送欢迎邮件
        self.send_welcome_email(email)
        return user

    def save_to_db(self, user):
        print(f"保存用户到数据库: {user}")

    def send_welcome_email(self, email):
        print(f"发送欢迎邮件到: {email}")

# 遵循单一职责
class User:
    """用户实体"""
    def __init__(self, name, email):
        self.name = name
        self.email = email

class UserRepository:
    """用户仓储"""
    def save(self, user):
        print(f"保存用户: {user.name}")
        return user

class EmailService:
    """邮件服务"""
    def send_welcome(self, email):
        print(f"发送欢迎邮件到: {email}")

class UserService:
    """用户服务(协调者)"""

    def __init__(self, repository, email_service):
        self.repository = repository
        self.email_service = email_service

    def register(self, name, email):
        user = User(name, email)
        self.repository.save(user)
        self.email_service.send_welcome(email)
        return user

# 开闭原则示例
class DiscountStrategy(ABC):
    """折扣策略(抽象)"""

    @abstractmethod
    def calculate(self, price):
        pass

class NoDiscount(DiscountStrategy):
    def calculate(self, price):
        return price

class PercentageDiscount(DiscountStrategy):
    def __init__(self, percentage):
        self.percentage = percentage

    def calculate(self, price):
        return price * (1 - self.percentage / 100)

class FixedDiscount(DiscountStrategy):
    def __init__(self, amount):
        self.amount = amount

    def calculate(self, price):
        return max(0, price - self.amount)

class Product:
    """产品类 - 对扩展开放"""

    def __init__(self, name, price, discount_strategy=None):
        self.name = name
        self.price = price
        self.discount_strategy = discount_strategy or NoDiscount()

    def get_final_price(self):
        return self.discount_strategy.calculate(self.price)

# 使用
product1 = Product("书", 100, PercentageDiscount(20))
product2 = Product("电子产品", 1000, FixedDiscount(100))
print(f"{product1.name}: ¥{product1.get_final_price()}")
print(f"{product2.name}: ¥{product2.get_final_price()}")

6.2 性能优化技巧

import timeit
from functools import lru_cache

class PerformanceOptimized:
    """展示性能优化技巧的类"""

    # 1. 使用 __slots__ 减少内存占用
    __slots__ = ['name', 'age', '_cache']

    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._cache = {}

    # 2. 缓存计算结果
    def expensive_method(self, n):
        """耗时计算(带缓存)"""
        if n in self._cache:
            return self._cache[n]

        # 模拟耗时计算
        result = sum(i * i for i in range(n))
        self._cache[n] = result
        return result

    # 3. 使用 @property 缓存
    @property
    @lru_cache(maxsize=1)
    def complex_property(self):
        """计算属性(全局缓存)"""
        print("计算复杂属性...")
        import time
        time.sleep(1)  # 模拟耗时操作
        return self.age * 2

# 比较 __slots__ 的内存优势
class NormalClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class SlotsClass:
    __slots__ = ['name', 'age']
    def __init__(self, name, age):
        self.name = name
        self.age = age

# 内存对比
import sys
normal_obj = NormalClass("Alice", 25)
slots_obj = SlotsClass("Alice", 25)

print(f"普通类内存: {sys.getsizeof(normal_obj.__dict__)} 字节")
# SlotsClass 没有 __dict__,节省内存
print(f"__slots__ 类内存: {sys.getsizeof(slots_obj)} 字节")

# 方法调用优化
class MethodOptimization:
    """方法调用优化"""

    def __init__(self):
        self.data = list(range(1000))

    def normal_method(self):
        """普通方法"""
        return sum(self.data)

    # 将频繁调用的方法缓存为局部变量
    def optimized_loop(self):
        data = self.data  # 局部变量访问更快
        total = 0
        for x in data:
            total += x
        return total

# 惰性初始化
class LazyInitialization:
    """惰性初始化"""

    def __init__(self):
        self._heavy_resource = None

    @property
    def heavy_resource(self):
        """只在需要时初始化"""
        if self._heavy_resource is None:
            print("初始化重量级资源...")
            self._heavy_resource = self._create_heavy_resource()
        return self._heavy_resource

    def _create_heavy_resource(self):
        """创建重量级资源"""
        import time
        time.sleep(0.1)  # 模拟耗时
        return ["resource"] * 1000

lazy = LazyInitialization()
print("对象已创建,但资源未初始化")
_ = lazy.heavy_resource  # 这里才真正初始化
print("资源已初始化")

七、总结

面向对象编程是 Python 的核心范式之一,掌握它能够让你写出更优雅、更易维护的代码。

核心要点回顾:

  1. 封装 - 隐藏实现细节,提供清晰的接口
  2. 使用 _ 和 __ 约定
  3. 通过 @property 控制属性访问

  4. 继承 - 代码复用和层次化设计

  5. 理解 MRO(方法解析顺序)
  6. 使用 super() 正确调用父类方法
  7. 多重继承需谨慎

  8. 多态 - 统一接口,不同实现

  9. 鸭子类型(Duck Typing)
  10. 抽象基类(ABC)

  11. 高级特性

  12. 描述符:控制属性访问
  13. 元类:控制类的创建
  14. 混入类:灵活的代码复用

  15. 设计原则

  16. SOLID 原则
  17. 组合优于继承
  18. 面向接口编程

选择建议: - 简单场景 → 数据类(dataclass)或命名元组 - 需要验证 → 使用描述符或 property - 复杂行为 → 完整的类设计 - 插件系统 → 元类或注册模式

面向对象不是银弹,但在合适的场景下,它能让你的代码更加模块化、可测试和可维护。最重要的是理解其背后的设计思想,而不是简单地堆砌语法。


本文由 尚先生 原创,转载请注明出处。

📖相关推荐

评论

0
暂无评论,来发表第一条评论吧

发表评论

登录 后发表评论