Python 三大神器:迭代器、生成器与装饰器详解
在 Python 中,迭代器(Iterator)、生成器(Generator)和装饰器(Decorator)是三个非常强大且常用的核心概念,被称为“Python 三大神器”。它们能让你写出更加高效、优雅和易读的 Pythonic 代码。本文将深入浅出地讲解这三者的概念、原理和用法。
1. 迭代器 (Iterator)
什么是迭代器?
迭代器是一个可以记住遍历位置的对象。它提供了一种惰性计算的机制,即需要时才生成下一个元素,而不是一次性将所有数据加载到内存中。这使得它可以处理巨大的数据集合而不会消耗大量内存。
迭代器对象必须实现两个特殊方法,它们合称为 迭代器协议 (Iterator Protocol):
-
__iter__(): 返回迭代器对象本身(通常是self)。 -
__next__(): 返回容器的下一个元素。如果没有更多元素,则抛出StopIteration异常。
如何创建和使用迭代器?
任何实现了 __iter__() 和 __next__() 方法的对象都是一个迭代器。
代码示例 1:自定义迭代器
python
class MyCounter:
"""一个简单的自定义迭代器,从 1 数到 n"""
def __init__(self, n):
self.n = n
self.current = 1
def __iter__(self):
# 返回迭代器对象自身
return self
def __next__(self):
# 返回下一个值
if self.current <= self.n:
value = self.current
self.current += 1
return value
else:
# 没有更多元素时,抛出 StopIteration 异常
raise StopIteration
# 使用自定义迭代器
counter = MyCounter(3)
for num in counter:
print(num)
# 输出:
# 1
# 2
# 3
# 你也可以手动调用 next()
counter2 = MyCounter(2)
print(next(counter2)) # 输出: 1
print(next(counter2)) # 输出: 2
# print(next(counter2)) # 再次调用会抛出 StopIteration
代码示例 2:使用内置迭代器
我们常用的 for...in 循环背后其实就是迭代器在工作。列表、元组、字典、字符串等可迭代对象 (Iterable) 都不是迭代器本身,但可以通过 iter() 函数获取它们的迭代器。
python
my_list = [1, 2, 3] # my_list 是可迭代对象 (Iterable),但不是迭代器 (Iterator) # iter(my_list) 会返回一个列表迭代器对象 list_iterator = iter(my_list) print(next(list_iterator)) # 输出: 1 print(next(list_iterator)) # 输出: 2 print(next(list_iterator)) # 输出: 3 # print(next(list_iterator)) # 抛出 StopIteration # for 循环的本质: # for element in iterable: # print(element) # 等价于: # iterator = iter(iterable) # while True: # try: # element = next(iterator) # print(element) # except StopIteration: # break
2. 生成器 (Generator)
什么是生成器?
生成器是一种特殊的迭代器,它使得编写迭代器变得更加简单和优雅。你不需要再像上面那样定义一个类并实现 __iter__() 和 __next__() 方法,而只需要使用一个包含 yield 关键字的函数。
生成器的核心是 yield 关键字。当函数执行到 yield 时,它会“暂停”并将值返回给调用者,同时保留当前所有的状态(局部变量、指令指针等)。下次调用 next() 时,函数会从上次 yield 的位置继续执行。
如何创建生成器?
创建生成器有两种主要方法:
-
生成器函数 (Generator Function):使用
def定义,但使用yield而不是return返回值。 -
生成器表达式 (Generator Expression):类似于列表推导式,但使用圆括号
()。
代码示例 3:生成器函数
python
def my_counter(n):
"""一个简单的生成器函数,功能与 MyCounter 类相同"""
current = 1
while current <= n:
yield current # 在此处暂停,返回 current 的值
current += 1
# 函数结束时,会自动引发 StopIteration
# 使用生成器函数
# 调用生成器函数并不会立即执行,而是返回一个生成器对象
gen = my_counter(3)
print(gen) # 输出: <generator object my_counter at 0x...>
# 生成器是迭代器,可以使用 next() 或 for 循环
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
print(next(gen)) # 输出: 3
# print(next(gen)) # 抛出 StopIteration
# 更常见的用法是直接用 for 循环
for num in my_counter(3):
print(num)
代码示例 4:生成器表达式 & 内存优势
python
# 列表推导式:一次性生成所有数据,占用内存
list_comp = [x * x for x in range(1000000)] # 内存中有一个包含100万个元素的列表
# 生成器表达式:惰性计算,几乎不占内存
gen_exp = (x * x for x in range(1000000)) # 几乎不占内存,只在需要时计算下一个平方数
print(next(gen_exp)) # 输出: 0
print(next(gen_exp)) # 输出: 1
print(next(gen_exp)) # 输出: 4
# 生成器在处理大规模数据(如大文件)时优势巨大
def read_large_file(file_path):
"""生成器函数,逐行读取大文件,避免内存溢出"""
with open(file_path, 'r', encoding='utf-8') as file:
for line in file:
yield line.strip()
# 使用方式
# for line in read_large_file('huge_log_file.txt'):
# process(line) # 一次只处理一行,内存友好
3. 装饰器 (Decorator)
什么是装饰器?
装饰器本质上是一个高阶函数,它接受一个函数作为参数,并返回一个新的函数(或可调用对象)。装饰器的作用是在不修改原函数代码的情况下,为函数增加新的功能,遵循“开放-封闭”原则。
装饰器通常用于添加日志、性能测试、事务处理、权限校验、缓存等通用功能。
如何创建和使用装饰器?
代码示例 5:简单的装饰器
python
def my_decorator(func):
"""一个简单的装饰器,在函数执行前后打印信息"""
def wrapper():
print("Something is happening before the function is called.")
func() # 执行被装饰的原始函数
print("Something is happening after the function is called.")
return wrapper # 返回内部包装好的函数
# 使用装饰器的语法糖 @
@my_decorator
def say_hello():
print("Hello!")
# 调用被装饰后的函数
say_hello()
# 输出:
# Something is happening before the function is called.
# Hello!
# Something is happening after the function is called.
# 不使用 @ 语法糖的等价写法:
# def say_hello():
# print("Hello!")
# say_hello = my_decorator(say_hello) # 手动包装
# say_hello()
代码示例 6:处理带参数的函数
python
def decorator_with_args(func):
"""一个能处理被装饰函数参数的装饰器"""
def wrapper(*args, **kwargs): # 使用 *args 和 **kwargs 接收任意参数
print(f"Decorator: About to call {func.__name__}")
result = func(*args, **kwargs) # 将参数原封不动传给原函数
print(f"Decorator: Finished calling {func.__name__}")
return result # 返回原函数的执行结果
return wrapper
@decorator_with_args
def greet(name):
return f"Hello, {name}!"
@decorator_with_args
def add(a, b):
return a + b
print(greet("Alice"))
# 输出:
# Decorator: About to call greet
# Decorator: Finished calling greet
# Hello, Alice!
print(add(5, 3))
# 输出:
# Decorator: About to call add
# Decorator: Finished calling add
# 8
代码示例 7:带参数的装饰器
python
def repeat(num_times):
"""装饰器工厂:接受参数,返回一个真正的装饰器"""
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result # 通常返回最后一次调用的结果
return wrapper
return decorator_repeat
@repeat(num_times=4)
def say_hi():
print("Hi!")
say_hi()
# 输出:
# Hi!
# Hi!
# Hi!
# Hi!
代码示例 8:内置装饰器 @functools.wraps
装饰器会掩盖原函数的元信息(如名字、文档字符串)。使用 functools.wraps 可以保留这些信息,这是一个最佳实践。
python
import functools
def smart_decorator(func):
@functools.wraps(func) # 保留 func 的元信息
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@smart_decorator
def example():
"""这是一个示例函数的文档字符串。"""
pass
print(example.__name__) # 输出: 'example' (没有 wraps 会输出 'wrapper')
print(example.__doc__) # 输出: '这是一个示例函数的文档字符串。'
总结与对比
| 特性 | 迭代器 (Iterator) | 生成器 (Generator) | 装饰器 (Decorator) |
|---|---|---|---|
| 本质 | 实现了 __iter__ 和 __next__ 的对象 |
特殊的迭代器,使用 yield |
高阶函数,接受函数并返回函数 |
| 目的 | 提供一种遍历集合元素的通用方式 | 简化迭代器创建,惰性求值,节省内存 | 动态增强函数功能,代码复用 |
| 关键语法 | __iter__(), __next__(), StopIteration |
yield, (x for x in ...) |
@decorator_name, 闭包 |
| 内存效率 | 高(惰性) | 非常高(按需生成值) | 不直接影响 |
| 主要优势 | 定义明确的遍历协议 | 语法简洁,内存友好,处理无限序列 | 不侵入原有代码,解耦功能 |
关系与协作:
-
生成器是迭代器的“语法糖”,让你更方便地创建迭代器。
-
装饰器可以装饰任何可调用对象,包括普通函数、类方法,甚至生成器函数。
-
你可以编写一个装饰器来增强生成器函数的行为(例如,自动处理
StopIteration或记录生成的值)。
掌握这“三大神器”是迈向高级 Python 程序员的必经之路,它们能极大地提升你代码的效率、可读性和可维护性。
更多推荐


所有评论(0)