学无止境

少年辛苦终身事,莫向光阴惰寸功。——唐·杜荀鹤《题弟侄书堂》


Python高级特性:生成器、迭代器、闭包与装饰器

1. 生成器(Generator)

1.1 生成器概念

生成器是Python中一种特殊的迭代器,它可以让我们以一种更优雅的方式构造迭代器。生成器不会一次性生成所有数据,而是在需要时才生成数据,这样可以节省内存空间。

1.2 创建生成器的方法

1.2.1 使用生成器表达式

# 列表推导式
numbers = [x * x for x in range(10)]  # 创建列表

# 生成器表达式
generator = (x * x for x in range(10))  # 创建生成器

1.2.2 使用yield关键字

def fibonacci(num):
    """生成斐波那契数列的生成器"""
    a, b = 0, 1
    for _ in range(num):
        yield b
        a, b = b, a + b

# 使用生成器
fib = fibonacci(10)
for num in fib:
    print(num)

1.3 生成器的特性与方法

1.3.1 next()方法

generator = (x for x in range(3))
print(next(generator))  # 0
print(next(generator))  # 1
print(next(generator))  # 2
# print(next(generator))  # StopIteration

1.3.2 send()方法

def counter():
    i = 0
    while True:
        value = yield i
        if value is not None:
            i = value
        else:
            i += 1

c = counter()
print(next(c))      # 0
print(c.send(10))   # 10
print(next(c))      # 11

1.4 生成器的优势

  1. 内存效率:按需生成数据
  2. 代码简洁:比迭代器的实现更简单
  3. 状态保存:保存上次运行状态

2. 迭代器(Iterator)

2.1 迭代器概念

迭代器是一个可以记住遍历位置的对象,它必须实现__iter__()__next__()方法。

2.2 可迭代对象与迭代器的区别

from collections.abc import Iterable, Iterator

# 可迭代对象示例
print(isinstance([], Iterable))    # True
print(isinstance({}, Iterable))    # True
print(isinstance('abc', Iterable)) # True

# 转换为迭代器
lst = [1, 2, 3]
iter_lst = iter(lst)
print(isinstance(iter_lst, Iterator))  # True

2.3 自定义迭代器

class CountDown:
    def __init__(self, start):
        self.start = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.start <= 0:
            raise StopIteration
        self.start -= 1
        return self.start + 1

# 使用自定义迭代器
counter = CountDown(5)
for num in counter:
    print(num)  # 5, 4, 3, 2, 1

3. 闭包(Closure)

3.1 闭包的定义

闭包是指延伸了作用域的函数,它可以访问定义函数时存在的非局部变量。

3.2 闭包的条件

  1. 必须有内嵌函数
  2. 内嵌函数必须引用外部函数的变量
  3. 外部函数必须返回内嵌函数

3.3 闭包示例

def make_averager():
    count = 0
    total = 0
    
    def averager(new_value):
        nonlocal count, total
        count += 1
        total += new_value
        return total / count
    
    return averager

avg = make_averager()
print(avg(10))  # 10.0
print(avg(20))  # 15.0
print(avg(30))  # 20.0

3.4 闭包中的变量作用域

def outer(x):
    def inner():
        nonlocal x  # 使用nonlocal关键字修改外部变量
        x += 1
        return x
    return inner

counter = outer(0)
print(counter())  # 1
print(counter())  # 2

4. 装饰器(Decorator)

4.1 装饰器基础

装饰器是可调用的对象,它接收一个函数作为参数并返回一个函数,用于增强函数功能。

4.2 简单装饰器

import functools
import time

def timer(func):
    @functools.wraps(func)  # 保留原函数的元信息
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"Function {func.__name__} took {end-start} seconds")
        return result
    return wrapper

@timer
def slow_function(n):
    time.sleep(n)
    return n

slow_function(1)  # Function slow_function took 1.0 seconds

4.3 带参数的装饰器

def repeat(times):
    def decorator(func):
        @functools.wraps(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("World")  # 打印三次 Hello, World

4.4 类装饰器

class Singleton:
    def __init__(self, cls):
        self._cls = cls
        self._instance = None

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            self._instance = self._cls(*args, **kwargs)
        return self._instance

@Singleton
class Database:
    def __init__(self):
        print("数据库连接创建")

# 测试单例模式
db1 = Database()
db2 = Database()
print(db1 is db2)  # True

5. 最佳实践与注意事项

5.1 生成器最佳实践

  • 处理大数据集时优先使用生成器
  • 注意捕获StopIteration异常
  • 合理使用send()方法进行双向通信

5.2 迭代器使用建议

  • 优先使用for循环而不是手动调用next()
  • 实现自定义迭代器时记得同时实现__iter__和__next__方法
  • 注意处理迭代完成的情况

5.3 闭包使用技巧

  • 谨慎使用nonlocal关键字
  • 注意闭包占用的内存资源
  • 合理利用闭包实现数据隐藏

5.4 装饰器编写原则

  • 保持装饰器的通用性
  • 使用functools.wraps保留原函数信息
  • 考虑装饰器的性能影响