面向对象和高级特性

2.1 类与对象

概念:什么是面向对象?

面向对象编程(OOP)是一种编程范式,将数据和操作数据的方法组织为"对象"。类是对象的蓝图/模板,通过实例化类来创建对象。OOP 的核心思想是将现实世界的事物抽象为程序中的对象,每个对象有自己的属性(数据)和方法(行为)。

面向对象基础

python 复制代码
# 类:模板/蓝图,用于创建对象
# 对象:类的实例

# 定义类
class Dog:
    """狗类"""

    # 类属性(所有实例共享)
    species = "犬科"

    # 实例方法(第一个参数是 self)
    def bark(self):
        return "汪汪汪!"

    def __init__(self, name, age):
        """初始化方法,创建对象时自动调用"""
        self.name = name    # 实例属性
        self.age = age

    def __str__(self):
        """返回字符串表示,用于 print"""
        return f"{self.name},{self.age}岁"

    def __repr__(self):
        """返回官方字符串表示,用于调试"""
        return f"Dog(name={self.name!r}, age={self.age!r})"

# 创建对象(实例化)
dog1 = Dog("旺财", 3)
dog2 = Dog("小白", 5)

# 访问属性和方法
print(dog1.name)           # 旺财
print(dog1.bark())         # 汪汪汪!
print(dog1.species)        # 犬科(类属性)

概念:self 是什么?

self 是对当前对象实例的引用,类似于其他语言中的 this指针。在实例方法中,self 用来访问对象的属性和其他方法。Python 会自动将 self 传递给实例方法的第一个参数。

python 复制代码
class Person:
    def __init__(self, name):
        self.name = name    # self 指向当前对象

    def greet(self):
        return f"你好,我是{self.name}"  # self 访问对象的属性和方法

概念:类属性 vs 实例属性

  • 类属性:定义在类中,所有对象共享,通常用于定义常量或类级别的数据
  • 实例属性 :定义在 \_init\\ 中,每个对象独立拥有
python 复制代码
class Dog:
    species = "犬科"          # 类属性:所有对象共享

    def __init__(self, name):
        self.name = name     # 实例属性:每个对象独立

dog1 = Dog("旺财")
dog2 = Dog("小白")

dog1.species = "猫科"       # 只影响 dog1,创建了新的实例属性
print(dog2.species)         # 犬科(不变)
print(Dog.species)          # 犬科(类属性不变)

概念:魔法方法(特殊方法)

魔法方法是以双下划线开头和结尾的特殊方法,也叫"Dunder Methods"。它们在特定操作发生时自动调用,例如 \\\\init\\ \\ 在创建对象时调用,\\\\str\\\\ 在 print 对象时调用。

python 复制代码
class Person:
    def __new__(cls, *args, **kwargs):
        """创建对象前调用,返回对象"""
        print("创建对象中...")
        return super().__new__(cls)

    def __init__(self, name):
        print("初始化对象...")
        self.name = name

    def __del__(self):
        """对象被删除时调用"""
        print(f"{self.name} 被删除了")

    def __call__(self):
        """使对象可调用,像函数一样"""
        return f"{self.name} 被调用了"

2.2 继承与多态

概念:什么是继承?

继承是面向对象的核心特性之一,允许我们定义一个类(子类)来继承另一个类(父类)的属性和方法。子类可以重用父类的代码,还可以添加自己的新属性和方法,或重写父类的方法。

单继承

python 复制代码
# 基类(父类)
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return "..."

# 派生类(子类)
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)    # 调用父类 __init__
        self.breed = breed        # 新增属性

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

dog = Dog("旺财", "哈士奇")
print(dog.name)      # 旺财(继承自父类)
print(dog.speak())   # 旺财 汪汪汪!(重写后的方法)

概念:多继承

Python 支持一个类继承多个父类,叫多继承。但多继承会增加复杂度,可能出现方法解析顺序(MRO)问题,使用时需要谨慎。

python 复制代码
class Flyable:
    def fly(self):
        return "我可以飞!"

class Swimmable:
    def swim(self):
        return "我可以游泳!"

# 多继承
class Duck(Animal, Flyable, Swimmable):
    pass

duck = Duck("唐老鸭")
print(duck.fly())   # 我可以飞!
print(duck.swim())  # 我可以游泳!

概念:MRO(方法解析顺序)

MRO 是 Python 用于决定在多继承情况下,应该从哪个父类开始查找方法/属性的顺序。可以通过 类名.mro() 或 类名.\\mro\\ 查看。

python 复制代码
class A:
    def greet(self):
        return "A"

class B(A):
    pass

class C(A):
    def greet(self):
        return "C"

class D(B, C):
    pass

print(D.mro())  # [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]
print(D().greet())  # C(按 MRO 顺序查找)

概念:super() 函数

super() 用于在子类中调用父类的方法,是实现类继承层级协作的关键。最常见的是在子类的 \\\\init\\ \\ 中调用 super().\\__init\\\\()。

python 复制代码
class Parent:
    def __init__(self, name):
        self.name = name

class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name)    # 调用父类方法
        self.age = age

# super() 也可以在普通方法中使用
class Child2(Parent):
    def greet(self):
        return f"Hello, {super().greet()}"

概念:什么是多态?

多态是指同一种方法调用在不同对象上有不同行为的特性。简单说就是"同一个接口,不同实现"。Python 天生支持多态,因为它是动态类型语言,不需要显式声明接口。

python 复制代码
# 同一个方法,不同对象有不同行为
class Cat(Animal):
    def speak(self):
        return "喵喵喵!"

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

# 统一接口
def make_noise(animal):
    print(animal.speak())

animals = [Dog("旺财"), Cat("咪咪"), Dog("小白")]
for animal in animals:
    make_noise(animal)
# 输出:
# 汪汪汪!
# 喵喵喵!
# 汪汪汪!

2.3 封装

概念:什么是封装?

封装是面向对象的三大特性之一(另两个是继承和多态)。封装的目的是隐藏对象的内部细节,只暴露必要的接口。Python 通过命名约定来实现封装:单下划线 \_ 表示"受保护",双下划线 \\__ 表示"私有"。

访问控制

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name          # 公有属性(可访问)
        self._age = age           # 保护属性(约定不直接访问)
        self.__phone = "123456"   # 私有属性(名字重整)

    def get_phone(self):          # 访问私有属性
        return self.__phone

    def _protected_method(self):   # 保护方法
        return "这是一个受保护的方法"

    def __private_method(self):    # 私有方法
        return "这是一个私有方法"

person = Person("Alice", 25)

print(person.name)            # Alice(正常访问)
print(person._age)           # 25(可以访问,但不推荐)
print(person.get_phone())    # 123456(通过方法访问)

# 名字重整:_Person__phone
print(person._Person__phone) # 123456(可以访问,但不推荐)

概念:property 装饰器

property 装饰器允许我们将方法当作属性来访问,实现"Getter"。配合 .setter 和 .deleter,可以实现完整的属性控制,实现数据封装和验证。

python 复制代码
class Person:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        """获取 name"""
        return self._name

    @name.setter
    def name(self, value):
        """设置 name"""
        if not value:
            raise ValueError("名字不能为空")
        self._name = value

    @name.deleter
    def name(self):
        """删除 name"""
        del self._name

person = Person("Alice")
print(person.name)     # Alice(调用 getter)

person.name = "Bob"    # 调用 setter
print(person.name)     # Bob

del person.name        # 调用 deleter

私有属性访问器模式

python 复制代码
class BankAccount:
    def __init__(self, balance):
        self.__balance = balance    # 私有属性

    def get_balance(self):           # getter
        return self.__balance

    def set_balance(self, value):   # setter
        if value < 0:
            raise ValueError("余额不能为负")
        self.__balance = value

    def deposit(self, amount):       # 业务方法
        if amount <= 0:
            raise ValueError("存款金额必须为正")
        self.__balance += amount

    def withdraw(self, amount):
        if amount > self.__balance:
            raise ValueError("余额不足")
        self.__balance -= amount

2.4 类方法与静态方法

概念:三种方法的区别

  • 实例方法:第一个参数是 self,只能通过实例调用,可以访问和修改实例属性
  • 类方法:第一个参数是 cls(类本身),可以通过类或实例调用,可以访问类属性但不能访问实例属性
  • 静态方法:没有任何默认参数,跟普通函数一样,可以通过类或实例调用,但不能访问类或实例属性

实例方法、类方法、静态方法对比

python 复制代码
class MyClass:
    class_attr = "类属性"

    def instance_method(self):
        """实例方法:第一个参数是 self"""
        return "实例方法", self

    @classmethod
    def class_method(cls):
        """类方法:第一个参数是类本身"""
        return "类方法", cls, cls.class_attr

    @staticmethod
    def static_method():
        """静态方法:没有默认参数"""
        return "静态方法"

# 调用
obj = MyClass()

obj.instance_method()           # 需要实例
MyClass.instance_method(obj)    # 也可以用实例调用

MyClass.class_method()          # 可以用类直接调用
obj.class_method()               # 也可以用实例调用

MyClass.static_method()         # 可以用类直接调用
obj.static_method()              # 也可以用实例调用

类方法的应用场景

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def from_dict(cls, data):
        """从字典创建对象"""
        return cls(data["name"], data["age"])

    @classmethod
    def from_string(cls, string):
        """从字符串创建对象"""
        name, age = string.split(",")
        return cls(name.strip(), int(age))

# 使用类方法创建对象
data = {"name": "Alice", "age": 25}
person1 = Person.from_dict(data)

person2 = Person.from_string("Bob, 30")

静态方法的应用场景

python 复制代码
class MathUtils:
    @staticmethod
    def add(a, b):
        """工具方法,与类相关但不依赖类或实例"""
        return a + b

    @staticmethod
    def is_valid_age(age):
        """判断年龄是否合法"""
        return 0 <= age <= 150

print(MathUtils.add(1, 2))           # 3
print(MathUtils.is_valid_age(25))   # True

2.5 特殊方法(魔术方法)

概念:什么是魔术方法?

魔术方法(Magic Methods)或特殊方法,是以双下划线 __ 开头和结尾的方法。它们不是普通方法,而是在特定操作时由 Python 自动调用的"钩子"。通过重写这些方法,可以让自定义对象支持 Python 的内置操作(如 +、==、len() 等)。

常用特殊方法一览

python 复制代码
class MyClass:
    def __init__(self, value):
        self.value = value

    # 字符串表示
    def __str__(self):
        return f"MyClass({self.value})"

    def __repr__(self):
        return f"MyClass(value={self.value!r})"

    # 比较运算符
    def __eq__(self, other):
        return self.value == other.value

    def __lt__(self, other):
        return self.value < other.value

    def __le__(self, other):
        return self.value <= other.value

    def __gt__(self, other):
        return self.value > other.value

    def __ge__(self, other):
        return self.value >= other.value

    # 算术运算符
    def __add__(self, other):
        return MyClass(self.value + other.value)

    def __sub__(self, other):
        return MyClass(self.value - other.value)

    def __mul__(self, other):
        return MyClass(self.value * other.value)

    def __truediv__(self, other):
        return MyClass(self.value / other.value)

    # 一元运算符
    def __neg__(self):
        return MyClass(-self.value)

    def __abs__(self):
        return MyClass(abs(self.value))

    # 长度和迭代
    def __len__(self):
        return len(self.value)

    def __iter__(self):
        return iter(self.value)

    def __contains__(self, item):
        return item in self.value

    # 调用
    def __call__(self):
        return f"调用了 MyClass({self.value})"

    # 索引访问
    def __getitem__(self, index):
        return self.value[index]

    def __setitem__(self, index, value):
        self.value[index] = value

    # 上下文管理
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

完整示例:向量类

python 复制代码
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"Vector({self.x}, {self.y})"

    def __repr__(self):
        return f"Vector({self.x!r}, {self.y!r})"

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

    def __abs__(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

v1 = Vector(3, 4)
v2 = Vector(1, 2)

print(v1)              # Vector(3, 4)
print(v1 + v2)         # Vector(4, 6)
print(v1 * 2)          # Vector(6, 8)
print(abs(v1))         # 5.0

2.6 装饰器

概念:什么是装饰器?

装饰器是 Python 的高级特性,它本质上是一个函数,用于在不修改原函数的情况下,给函数添加新的功能。可以把装饰器理解为"包装"函数的高阶函数。装饰器广泛用于日志记录、性能测试、权限验证、缓存等场景。

函数装饰器

python 复制代码
# 装饰器是一个函数,接收函数作为参数,返回新函数

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("调用前")
        result = func(*args, **kwargs)
        print("调用后")
        return result
    return wrapper

@my_decorator
def say_hello(name):
    print(f"Hello, {name}!")

# 等价于
# say_hello = my_decorator(say_hello)

say_hello("Alice")
# 输出:
# 调用前
# Hello, Alice!
# 调用后

概念:装饰器带参数

装饰器工厂(Decorator Factory)是返回装饰器的函数。通过装饰器工厂可以给装饰器传递参数,实现更灵活的功能配置。

python 复制代码
def repeat(times):
    """装饰器工厂:返回装饰器"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")
# 输出: Hello, Alice! 三次

类装饰器

python 复制代码
class MyDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("调用前")
        return self.func(*args, **kwargs)

@MyDecorator
def say_hello(name):
    print(f"Hello, {name}!")

概念:functools.wraps 的作用

装饰器在包装原函数时,会丢失原函数的元信息(如 \\__name\\、\\doc\\ 等)。使用 @functools.wraps(func) 可以保留这些元信息,对调试和文档生成很重要。

python 复制代码
import functools

def my_decorator(func):
    @functools.wraps(func)    # 保留原函数的信息
    def wrapper(*args, **kwargs):
        print("调用前")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def say_hello(name):
    """问候函数"""
    print(f"Hello, {name}!")

print(say_hello.__name__)    # say_hello(而不是 wrapper)
print(say_hello.__doc__)     # 问候函数

常见装饰器

python 复制代码
# property 装饰器(已在 2.3 讲过)

# classmethod 装饰器(已在 2.4 讲过)

# staticmethod 装饰器(已在 2.4 讲过)

# 缓存装饰器
import functools

def cache(func):
    cache_dict = {}
    @functools.wraps(func)
    def wrapper(*args):
        if args not in cache_dict:
            cache_dict[args] = func(*args)
        return cache_dict[args]
    return wrapper

@cache
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

2.7 生成器与迭代器

概念:什么是迭代器协议?

迭代器是实现了 \\__iter\\\\ 和 \\__next\\\\ 两个方法的对象。迭代器协议是 Python 中用于遍历集合的标准方式,通过 next() 函数获取下一个元素,当没有更多元素时抛出 StopIteration 异常。

迭代器协议

python 复制代码
# 迭代器:实现了 __iter__ 和 __next__ 的对象

class Counter:
    def __init__(self, limit):
        self.limit = limit
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.limit:
            result = self.current
            self.current += 1
            return result
        raise StopIteration    # 迭代结束

counter = Counter(5)
for i in counter:
    print(i)  # 0, 1, 2, 3, 4

概念:什么是生成器?

生成器是一种特殊的迭代器,使用 yield 关键字来返回值。与普通函数返回后结束不同,生成器函数在执行过程中可以暂停和恢复,yield 会保存函数的状态。生成器非常适合处理大数据流,可以节省内存。

生成器函数

python 复制代码
# 使用 yield 的函数就是生成器函数

def countdown(n):
    """倒数生成器"""
    while n > 0:
        yield n
        n -= 1

for num in countdown(5):
    print(num)  # 5, 4, 3, 2, 1

# 生成器是迭代器的一种,更简单
gen = countdown(3)
print(next(gen))  # 5
print(next(gen))  # 4
print(next(gen))  # 3
print(next(gen))  # StopIteration

生成器表达式

python 复制代码
# 类似列表推导式,但用圆括号,返回生成器
squares = (x**2 for x in range(5))
print(next(squares))  # 0
print(next(squares))  # 1

# 节省内存,适合大数据
million_squares = (x**2 for x in range(1000000))
# 不占用额外内存,直到迭代时才计算

概念:yield from

yield from 是 Python 3.3 引入的新语法,用于简化在生成器中委托给另一个生成器。它允许我们直接"透传"yield 操作给子生成器,而不需要使用循环。

python 复制代码
def flatten(nested):
    """扁平化嵌套列表"""
    for item in nested:
        if isinstance(item, list):
            yield from flatten(item)
        else:
            yield item

result = list(flatten([1, [2, 3], [4, [5, 6]]]))
print(result)  # [1, 2, 3, 4, 5, 6]

迭代工具

python 复制代码
from itertools import count, cycle, repeat, chain, zip_longest, islice

# count: 无限计数
for i in zip(range(5), count(10)):
    print(i)  # (0, 10), (1, 11), (2, 12), (3, 13), (4, 14)
### 文章摘要生成方法

确定文章核心主题和关键论点,确保摘要涵盖主要观点。避免冗余细节,聚焦于文章的核心价值。

提取文章中的关键数据、案例或结论,用简洁语言概括。保持逻辑连贯性,使读者能快速理解文章主旨。

检查摘要是否独立完整,无需依赖原文即可传达核心信息。确保语言精炼,控制在指定字数内。

对于技术或学术文章,突出研究方法、发现或创新点。非专业读者也能通过摘要把握文章要点。

将摘要分为背景、方法、结果、结论四个部分,每部分用1-2句话概括。这种结构适用于大多数学术性文章。
# cycle: 无限循环
for i, c in zip(range(8), cycle("ABC")):
    print(f"{i}: {c}")

# repeat: 重复元素
for item in repeat("A", 3):
    print(item)  # A, A, A

# chain: 连接多个迭代器
for item in chain([1, 2], ['a', 'b']):
    print(item)  # 1, 2, a, b

# islice: 切片迭代器
import itertools
for item in itertools.islice(range(10), 2, 8, 2):
    print(item)  # 2, 4, 6

2.8 上下文管理器

概念:什么是上下文管理器?

上下文管理器是一种支持 with 语句的对象,它在进入代码块前执行"进入"操作,在退出代码块后执行"退出"操作。最常见的用途是资源管理:确保文件、网络连接、锁等资源在使用后正确关闭或释放,即使发生异常也不会遗漏。

with 语句

python 复制代码
# 上下文管理器:实现了 __enter__ 和 __exit__ 的对象
# 用于资源管理,自动获取和释放资源

with open("test.txt", "w") as f:
    f.write("Hello")
# 文件自动关闭

# 等价于
f = open("test.txt", "w")
try:
    f.write("Hello")
finally:
    f.close()

类实现上下文管理器

python 复制代码
class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()
        # return True 可以抑制异常(但不推荐)

with FileManager("test.txt", "w") as f:
    f.write("Hello")

contextlib 模块

python 复制代码
import contextlib

# 1. contextmanager 装饰器
@contextlib.contextmanager
def managed_resource():
    print("获取资源")
    yield "资源"
    print("释放资源")

with managed_resource() as resource:
    print(f"使用 {resource}")

# 输出:
# 获取资源
# 使用 资源
# 释放资源

# 2. closing:自动调用 close()
@contextlib.closing
def open_file():
    f = open("test.txt", "w")
    return f

with open_file() as f:
    f.write("Hello")

# 3. suppress:忽略指定异常
with contextlib.suppress(FileNotFoundError):
    os.remove("nonexistent.txt")

# 4. redirect_stdout:重定向标准输出
import io
with contextlib.redirect_stdout(io.StringIO()) as f:
    print("Hello")
    output = f.getvalue()

2.9 类型注解

概念:什么是类型注解?

类型注解是 Python 3.5+ 引入的特性,允许在代码中为变量、函数参数和返回值添加类型提示。这是可选的,不会影响代码运行,但可以帮助 IDE 进行代码补全、类型检查(如 mypy),并使代码更易读。

基础类型注解

python 复制代码
# 变量注解
name: str = "Alice"
age: int = 25
height: float = 1.68
is_student: bool = True

# 函数注解
def greet(name: str) -> str:
    return f"Hello, {name}"

def add(a: int, b: int) -> int:
    return a + b

概念:复杂类型注解

typing 模块提供了用于复杂类型注解的工具,包括 List、Dict、Tuple、Optional、Union、Callable 等,适用于集合类型、可选值、联合类型和函数类型等场景。

复杂类型注解

python 复制代码
from typing import List, Dict, Tuple, Set, Optional, Union, Callable

# 列表
numbers: List[int] = [1, 2, 3]

# 字典
person: Dict[str, Union[str, int]] = {"name": "Alice", "age": 25}

# 元组
point: Tuple[int, int] = (3, 4)

# 集合
unique_numbers: Set[int] = {1, 2, 3}

# 可选类型
name: Optional[str] = None  # 等价于 Union[str, None]

# 联合类型
result: Union[int, str] = 42

# 可调用对象
def callback(func: Callable[[int, int], int]):
    return func(1, 2)

# 匿名函数类型
operation: Callable[[int, int], int] = lambda x, y: x + y

typing 模块常用类型

python 复制代码
from typing import Any, NoReturn, TypeVar, Generic, Iterator

# Any:任意类型
def func(x: Any) -> Any:
    return x

# NoReturn:无返回值
def error() -> NoReturn:
    raise ValueError("错误")

# TypeVar:类型变量
T = TypeVar('T')
def first(lst: List[T]) -> Optional[T]:
    return lst[0] if lst else None

# 泛型
from typing import TypeVar
T = TypeVar('T')

class Stack(Generic[T]):
    def __init__(self):
        self._items: List[T] = []

    def push(self, item: T):
        self._items.append(item)

    def pop(self) -> T:
        return self._items.pop()

运行时类型检查

python 复制代码
# 类型注解不影响运行时,使用 typing.get_type_hints() 获取

def greet(name: str) -> str:
    return f"Hello, {name}"

import typing
hints = typing.get_type_hints(greet)
print(hints)  # {'name': <class 'str'>, 'return': <class 'str'>}

# 第三方库如 pydantic 可以进行运行时验证

2.10 描述符协议

概念:什么是描述符?

描述符是 Python 最强大也最隐秘的特性之一。它是一种类属性,通过实现 \\__get\\\\ 、\\__set\\\\ 、\\__delete\\\\ 方法来控制对另一个类属性的访问。property 装饰器就是基于描述符协议实现的。

描述符是什么

python 复制代码
# 描述符:实现了 __get__ 和 __set__ 的类属性
# 用于控制属性的访问、修改和删除

class Score:
    def __init__(self):
        self._score = 0

    def __get__(self, instance, owner):
        print(f"获取 score: {self._score}")
        return self._score

    def __set__(self, instance, value):
        if value < 0 or value > 100:
            raise ValueError("分数必须在 0-100 之间")
        print(f"设置 score: {value}")
        self._score = value

    def __delete__(self, instance):
        print("删除 score")
        del self._score

class Student:
    score = Score()    # 类属性是描述符

student = Student()
student.score = 95     # 设置 score: 95
print(student.score)  # 获取 score: 95 / 95
del student.score      # 删除 score

property vs 描述符

python 复制代码
# property 是描述符的简化形式

class Person:
    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

# 等价的描述符实现
class NameDescriptor:
    def __get__(self, instance, owner):
        return instance._name

    def __set__(self, instance, value):
        instance._name = value

class Person2:
    name = NameDescriptor()

2.11 元类基础

概念:什么是元类?

元类是"类的类"。普通类定义了如何创建对象,而元类定义了如何创建类。默认情况下,所有类都是用 type 作为元类创建。通过自定义元类,我们可以在类创建时修改类的行为,比如自动注册类、强制子类实现某些方法等。

type 创建类

python 复制代码
# type 三个参数:类名、基类元组、属性字典
MyClass = type("MyClass", (), {"value": 42})
obj = MyClass()
print(obj.value)  # 42

自定义元类

python 复制代码
# 元类:类的类,用于控制类的创建

class MyMeta(type):
    def __new__(mcs, name, bases, attrs):
        print(f"创建类: {name}")
        # 可以修改类的属性
        attrs["class_name"] = name
        return super().__new__(mcs, name, bases, attrs)

class MyClass(metaclass=MyMeta):
    pass

# 输出: 创建类: MyClass
print(MyClass.class_name)  # MyClass

元类应用场景

python 复制代码
# 1. 注册类
class RegistryMeta(type):
    registry = {}

    def __new__(mcs, name, bases, attrs):
        cls = super().__new__(mcs, name, bases, attrs)
        if name != "Base":
            RegistryMeta.registry[name] = cls
        return cls

class Base(metaclass=RegistryMeta):
    pass

class Dog(Base):
    pass

class Cat(Base):
    pass

print(RegistryMeta.registry)  # {'Dog': <class '__main__.Dog'>, 'Cat': <class '__main__.Cat'>}

# 2. 强制实现方法
class RequireMethodMeta(type):
    def __init__(cls, name, bases, attrs):
        required_methods = ["validate", "process"]
        for method in required_methods:
            if method not in attrs:
                raise TypeError(f"子类必须实现 {method} 方法")
        super().__init__(name, bases, attrs)

2.12 组合与聚合

概念:组合 vs 继承

  • 继承(Is-A):子类是父类的一种,如 Dog is an Animal。适合"是一个"的关系
  • 组合(Has-A):类包含另一个类的实例,如 Car has an Engine。适合"有一个"的关系

面向对象设计中,优先使用组合而不是继承,因为组合更灵活、耦合更低。

组合(Has-A)

python 复制代码
# 组合:一个类包含另一个类的实例
# "拥有"关系,生命周期一致

class Engine:
    def start(self):
        return "发动机启动"

class Car:
    def __init__(self):
        self.engine = Engine()    # 组合:Car 拥有 Engine

    def start(self):
        return self.engine.start()

car = Car()
print(car.start())  # 发动机启动

聚合(Uses-A)

python 复制代码
# 聚合:一个类使用另一个类的实例
# "使用"关系,生命周期独立

class Teacher:
    def teach(self):
        return " teaching"

class School:
    def __init__(self, teacher):
        self.teacher = teacher    # 聚合:School 使用 Teacher

school = School(Teacher())

组合 vs 继承

python 复制代码
# 继承(Is-A):"是一个"
# Dog 是 Animal,所以 Dog 继承 Animal

# 组合(Has-A):"有一个"
# Car 有 Engine,所以 Car 包含 Engine

# 优先使用组合,因为:
# 1. 更灵活,可以在运行时替换组件
# 2. 避免继承的脆弱性(父类变化影响子类)
# 3. 减少耦合

常见设计模式

概念:单例模式

单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点。常用于配置管理器、数据库连接池、日志器等。

单例模式

python 复制代码
class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # True(同一个对象)

概念:工厂模式

工厂模式是一种创建型设计模式,通过一个工厂类来创建对象,而不是直接使用构造函数。这样可以将对象的创建与使用解耦。

工厂模式

python 复制代码
class Dog:
    def speak(self):
        return "汪汪汪"

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

class AnimalFactory:
    @staticmethod
    def create_animal(animal_type):
        if animal_type == "dog":
            return Dog()
        elif animal_type == "cat":
            return Cat()
        raise ValueError(f"未知的动物类型: {animal_type}")

animal = AnimalFactory.create_animal("dog")
print(animal.speak())  # 汪汪汪

---

### 概念:观察者模式

观察者模式是一种行为型设计模式,定义了对象间的一对多依赖关系。当一个对象状态改变时,所有依赖它的对象都会收到通知并自动更新。常用于事件系统、消息订阅、GUI 交互等场景。

### 观察者模式

```python
class Subject:
    def __init__(self):
        self._observers = []

    def attach(self, observer):
        if observer not in self._observers:
            self._observers.append(observer)

    def detach(self, observer):
        self._observers.remove(observer)

    def notify(self, message=None):
        for observer in self._observers:
            if message:
                observer.update(message)
            else:
                observer.update()

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

    def update(self, message):
        print(f"{self.name} 收到通知: {message}")

# 使用
subject = Subject()
observer1 = Observer("观察者1")
observer2 = Observer("观察者2")

subject.attach(observer1)
subject.attach(observer2)
subject.notify("事件发生了")
# 输出:
# 观察者1 收到通知: 事件发生了
# 观察者2 收到通知: 事件发生了

subject.detach(observer1)
subject.notify("又发生了一件事")
# 输出:
# 观察者2 收到通知: 又发生了一件事

概念:策略模式

策略模式是一种行为型设计模式,定义了算法家族,分别封装起来,让它们可以互相替换。策略模式使算法可以独立于使用它的客户端而变化。常用于排序算法选择、支付方式选择、折扣计算等场景。

策略模式

python 复制代码
from abc import ABC, abstractmethod

# 抽象策略
class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

# 具体策略
class AlipayStrategy(PaymentStrategy):
    def pay(self, amount):
        print(f"使用支付宝支付 {amount} 元")

class WechatPayStrategy(PaymentStrategy):
    def pay(self, amount):
        print(f"使用微信支付 {amount} 元")

class CreditCardStrategy(PaymentStrategy):
    def __init__(self, card_number):
        self.card_number = card_number

    def pay(self, amount):
        print(f"使用信用卡 {self.card_number[-4:]} 支付 {amount} 元")

# 上下文
class ShoppingCart:
    def __init__(self):
        self.items = []
        self.payment_strategy = None

    def add_item(self, item, price):
        self.items.append((item, price))

    def set_payment(self, strategy):
        self.payment_strategy = strategy

    def checkout(self):
        total = sum(price for _, price in self.items)
        if self.payment_strategy:
            self.payment_strategy.pay(total)
        else:
            print("请选择支付方式")

# 使用
cart = ShoppingCart()
cart.add_item("商品1", 100)
cart.add_item("商品2", 200)

cart.set_payment(AlipayStrategy())
cart.checkout()  # 使用支付宝支付 300 元

cart.set_payment(CreditCardStrategy("1234567890123456"))
cart.checkout()  # 使用信用卡 3456 支付 300 元

概念:装饰器模式(进阶)

装饰器模式允许动态地给对象添加职责,比继承更加灵活。它通过将对象包装在装饰器类中,在调用原始对象方法的同时添加新行为。

装饰器模式

python 复制代码
# 组件接口
class Coffee:
    def cost(self):
        return 5

# 基础组件
class SimpleCoffee(Coffee):
    def cost(self):
        return 5

# 装饰器基类
class CoffeeDecorator(Coffee):
    def __init__(self, coffee):
        self._coffee = coffee

    def cost(self):
        return self._coffee.cost()

# 具体装饰器
class MilkDecorator(CoffeeDecorator):
    def cost(self):
        return self._coffee.cost() + 2

class SugarDecorator(CoffeeDecorator):
    def cost(self):
        return self._coffee.cost() + 1

class WhipDecorator(CoffeeDecorator):
    def cost(self):
        return self._coffee.cost() + 3

# 使用
coffee = SimpleCoffee()
print(f"美式咖啡: {coffee.cost()}")  # 5

coffee_with_milk = MilkDecorator(coffee)
print(f"加奶咖啡: {coffee_with_milk.cost()}")  # 7

coffee_with_milk_and_sugar = SugarDecorator(MilkDecorator(coffee))
print(f"加奶加糖: {coffee_with_milk_and_sugar.cost()}")  # 8

# 链式装饰
whip_milk_coffee = WhipDecorator(MilkDecorator(SimpleCoffee()))
print(f"奶咖加奶油: {whip_milk_coffee.cost()}")  # 10

概念:适配器模式

适配器模式是一种结构型设计模式,用于将一个类的接口转换成客户端期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

适配器模式

python 复制代码
# 目标接口
class Target:
    def request(self):
        return "目标接口的请求"

# 需要适配的类
class Adaptee:
    def specific_request(self):
        return ".kcapeD tpecretxe si reh troP"

# 类适配器(使用继承)
class ClassAdapter(Adaptee, Target):
    def request(self):
        result = self.specific_request()
        return result[::-1]  # 反转字符串

# 对象适配器(使用组合)
class ObjectAdapter(Target):
    def __init__(self, adaptee):
        self._adaptee = adaptee

    def request(self):
        result = self._adaptee.specific_request()
        return result[::-1]

# 使用
target = Target()
print(target.request())  # 目标接口的请求

adapter1 = ClassAdapter()
print(adapter1.request())  # Python 的是特别好的

adapter2 = ObjectAdapter(Adaptee())
print(adapter2.request())  # Python 的是特别好的

概念:生成器模式

生成器模式是一种创建型设计模式,用于分步骤创建复杂对象。生成器允许使用相同的构建过程创建不同形式的产品。

生成器模式

python 复制代码
# 产品
class House:
    def __init__(self):
        self.foundation = None
        self.structure = None
        self.roof = None
        self.interior = None

    def __str__(self):
        return f"房子: 地基={self.foundation}, 结构={self.structure}, 屋顶={self.roof}, 装修={self.interior}"

# 抽象生成器
class HouseBuilder:
    def build_foundation(self):
        pass
    def build_structure(self):
        pass
    def build_roof(self):
        pass
    def build_interior(self):
        pass
    def get_result(self):
        pass

# 具体生成器
class WoodenHouseBuilder(HouseBuilder):
    def __init__(self):
        self.house = House()

    def build_foundation(self):
        self.house.foundation = "木质地基"
        return self

    def build_structure(self):
        self.house.structure = "木质框架"
        return self

    def build_roof(self):
        self.house.roof = "木质屋顶"
        return self

    def build_interior(self):
        self.house.interior = "木质装修"
        return self

    def get_result(self):
        return self.house

# 导演
class HouseDirector:
    def __init__(self, builder):
        self.builder = builder

    def construct_simple_house(self):
        return (self.builder
                .build_foundation()
                .build_structure()
                .build_roof())

    def construct_full_house(self):
        return (self.builder
                .build_foundation()
                .build_structure()
                .build_roof()
                .build_interior())

# 使用
builder = WoodenHouseBuilder()
director = HouseDirector(builder)

simple_house = director.construct_simple_house()
print(simple_house)
# 房子: 地基=木质地基, 结构=木质框架, 屋顶=木质屋顶, 装修=None

full_house = director.construct_full_house()
print(full_house)
# 房子: 地基=木质地基, 结构=木质框架, 屋顶=木质屋顶, 装修=木质装修

概念:模板方法模式

模板方法模式是一种行为型设计模式,定义算法骨架,将某些步骤推迟到子类中实现。模板方法使子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。

模板方法模式

python 复制代码
from abc import ABC, abstractmethod

# 抽象基类
class DataMiner(ABC):
    # 模板方法
    def mine(self, path):
        file = self.open_file(path)
        data = self.extract_data(file)
        parsed = self.parse_data(data)
        analysis = self.analyze_data(parsed)
        self.send_report(analysis)
        self.close_file(file)

    # 抽象方法(子类必须实现)
    @abstractmethod
    def open_file(self, path):
        pass

    @abstractmethod
    def extract_data(self, file):
        pass

    @abstractmethod
    def parse_data(self, data):
        pass

    @abstractmethod
    def close_file(self, file):
        pass

    # 具体方法(子类可以重写)
    def analyze_data(self, data):
        return f"分析数据: {len(data)} 条记录"

    def send_report(self, analysis):
        print(f"发送报告: {analysis}")

# 具体实现
class PDFDataMiner(DataMiner):
    def open_file(self, path):
        print(f"打开 PDF: {path}")
        return {"type": "pdf", "path": path}

    def extract_data(self, file):
        print("从 PDF 提取数据")
        return ["数据1", "数据2", "数据3"]

    def parse_data(self, data):
        print("解析 PDF 数据")
        return [d.upper() for d in data]

    def close_file(self, file):
        print(f"关闭 PDF: {file['path']}")

class CSVDataMiner(DataMiner):
    def open_file(self, path):
        print(f"打开 CSV: {path}")
        return {"type": "csv", "path": path}

    def extract_data(self, file):
        print("从 CSV 提取数据")
        return ["记录A", "记录B"]

    def parse_data(self, data):
        print("解析 CSV 数据")
        return [d.lower() for d in data]

    def close_file(self, file):
        print(f"关闭 CSV: {file['path']}")

# 使用
print("=== PDF 挖掘 ===")
pdf_miner = PDFDataMiner()
pdf_miner.mine("/path/to/file.pdf")

print("\n=== CSV 挖掘 ===")
csv_miner = CSVDataMiner()
csv_miner.mine("/path/to/file.csv")
相关推荐
Lauren_Blueblue2 小时前
第十六届蓝桥杯省赛Python研究生组-F串
python·算法·蓝桥杯·算法基础
曲幽2 小时前
告别手写 API 胶水代码:FastAPI 与 Vue 的“契约自动机” OpenAPI 实战
python·typescript·vue·fastapi·web·swagger·openapi·codegen
鲸渔2 小时前
【C++ 入门】第一个程序:Hello World 与基本语法规则
开发语言·c++·算法
阿捞22 小时前
python-langchain框架(3-20-智能问答ZeroShot_ReAct Agent 从零搭建)
python·react.js·langchain
数据知道2 小时前
claw-code 源码分析:从 REPL 到服务端——CLI / HTTP(SSE) / LSP 多入口如何共享同一颗 runtime 心?
python·网络协议·http·ai·里氏替换原则·claude code
不解不惑2 小时前
gemma4 实现ASR语音识别
人工智能·python·语音识别
来自远方的老作者2 小时前
第8章 流程控制-8.2 选择结构
开发语言·python·选择结构
kaico20182 小时前
python常用标准库
开发语言·python
TTGGGFF2 小时前
SnapTranslate 2.0:轻量级全场景划词翻译——添加生词本以及生词本复习AI助手功能!
python·划词翻译·git开源