Day 12:迭代器/生成器/装饰器
🎯 学习目标:掌握 Python 三大高级特性——迭代器、生成器、装饰器
1. 深浅拷贝回顾
import copy
# 浅拷贝 vs 深拷贝回顾
original = [1, 2, [10, 20, 30]]
# 浅拷贝:只拷贝外层
shallow = copy.copy(original)
shallow[0] = 100 # 不影响 original[0]
shallow[2][0] = 999 # ⚠️ 影响 original[2][0]!
print(original) # [1, 2, [999, 20, 30]]
# 深拷贝:递归拷贝全部
deep = copy.deepcopy(original)
deep[0] = 200 # 不影响 original
deep[2][0] = 888 # 也不影响 original
print(original) # [1, 2, [10, 20, 30]] ✋ 完全不变
2. 迭代器 Iterator
2.1 可迭代对象 vs 迭代器
# 包括:list, tuple, str, dict, set, range, 文件对象...
nums = [1, 2, 3]
print(hasattr(nums, '__iter__')) # True(可迭代对象)
# 迭代器(Iterator):可以被 next() 逐个取值的对象
it = iter(nums) # 获取迭代器
print(hasattr(it, '__next__')) # True(迭代器)
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
# next(it) → StopIteration(没有更多元素了)
2.2 for 循环的本质
# for item in obj 本质上做的事情:
nums = [1, 2, 3]
# 等价于:
it = iter(nums) # 1. 获取迭代器
while True:
try:
item = next(it) # 2. 逐个获取元素
print(item) # 3. 执行循环体
except StopIteration:
break # 4. 没有更多元素,退出
2.3 自定义迭代器
class CountDown:
"""倒计时迭代器"""
def __init__(self, start):
self.current = start
def __iter__(self):
"""返回迭代器对象(就是自身)"""
return self
def __next__(self):
"""返回下一个值"""
if self.current <= 0:
raise StopIteration # 终止信号
value = self.current
self.current -= 1
return value
# 使用
for num in CountDown(5):
print(num, end=" ") # 5 4 3 2 1
3. 生成器 Generator ⭐
生成器是最 Pythonic 的创建迭代器的方式。
3.1 生成器函数(yield)
# 用 yield 代替 return 就是生成器
def countdown(n):
while n > 0:
yield n # 暂停并返回值,状态保留
n -= 1
# 调用生成器函数 → 返回 generator 对象
gen = countdown(3)
print(type(gen)) # <class 'generator'>
# 逐个取值
print(next(gen)) # 3
print(next(gen)) # 2
print(next(gen)) # 1
# 可以 for 循环
for num in countdown(5):
print(num) # 5 4 3 2 1
3.2 yield 的执行流程
def demo_generator():
print(">>> 开始")
yield 1
print(">>> 恢复执行")
yield 2
print(">>> 再次恢复")
yield 3
print(">>> 结束")
gen = demo_generator()
print("调用 next 第 1 次")
print(next(gen))
# 1 ← yield 在这里暂停
print("调用 next 第 2 次")
print(next(gen))
# 2
print("调用 next 第 3 次")
print(next(gen))
# print(next(gen)) # StopIteration
3.3 斐波那契数列(生成器版)
def fibonacci(limit=None):
"""生成斐波那契数列"""
a, b = 0, 1
count = 0
while limit is None or count < limit:
yield a
a, b = b, a + b
count += 1
# 前 10 个
for num in fibonacci(10):
print(num, end=" ")
# print(num)
3.4 send 方法
def accumulator():
"""累加器:可以接收外部传入的值"""
total = 0
while True:
value = yield total # 接收 send 传来的值,并 yield 当前总数
if value is None:
break
total += value
acc = accumulator()
print(next(acc)) # 0(启动生成器)
print(acc.send(10)) # 10(传入 10)
print(acc.send(20)) # 30(累加 20)
print(acc.send(5)) # 35(累加 5)
acc.close() # 关闭生成器
yield vs return
return:函数结束,一次性返回
yield:函数暂停,可以多次产出,状态保留
4. 命名空间与四种作用域(深入)
x = "global" # 全局
def outer():
x = "enclosing" # 嵌套作用域
def middle():
x = "enclosing2" # 也属于嵌套
def inner():
x = "local" # 局部
print(f"inner: {x}")
inner()
print(f"middle: {x}")
middle()
print(f"outer: {x}")
outer()
print(f"global: {x}")
# global: global
5. 装饰器 Decorator ⭐⭐
装饰器本质:一个接受函数、返回新函数的函数。
5.1 闭包实现装饰器(手动版)
def my_decorator(func):
"""装饰器:包装原函数"""
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__} 之前...")
result = func(*args, **kwargs)
print(f"调用 {func.__name__} 之后...")
return result
return wrapper
def greet(name):
return f"Hello, {name}!"
# 手动装饰
greet = my_decorator(greet)
print(greet("Python"))
# Hello, Python!
5.2 语法糖 @
@my_decorator # ← 等价于 greet = my_decorator(greet)
def greet(name):
return f"Hello, {name}!"
5.3 实用装饰器示例
import time
import functools
# 计时器
def timer(func):
@functools.wraps(func) # 保留原函数的元信息
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} 执行耗时:{elapsed:.4f} 秒")
return result
return wrapper
# 日志
def logger(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"[LOG] 调用 {func.__name__}({args}, {kwargs})")
result = func(*args, **kwargs)
print(f"[LOG] {func.__name__} 返回 {result}")
return result
return wrapper
# 重试
def retry(max_attempts=3):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts:
raise
print(f"第 {attempt} 次失败:{e},重试中...")
time.sleep(1)
return wrapper
return decorator
# 叠加使用
@timer
@logger
@retry(max_attempts=3)
def fetch_data(url):
import random
if random.random() < 0.5:
raise ConnectionError("网络错误")
return f"从 {url} 获取的数据"
5.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("连接数据库...")
self.connected = True
# 多次"实例化"实际返回同一个对象
db1 = Database() # 输出:连接数据库...
db2 = Database() # 不输出,直接返回已有实例
print(db1 is db2) # True
📝 三者关系
graph TB Iter[迭代器 Iterator<br/>__iter__ + __next__] Gen[生成器 Generator<br/>yield 语法糖] Clo[闭包 Closure<br/>函数 + 环境] Dec[装饰器 Decorator<br/>@ 语法糖] Iter --> |"更简洁的实现方式"| Gen Clo --> |"核心机制"| Dec Clo -.-> |"常见实现方式"| Gen
速记卡(面试闪卡)
Q1:一句话讲清「Day 12:迭代器/生成器/装饰器」到底是什么?
A:迭代器用 iter/next 逐个取值,生成器用 yield 简写迭代器,装饰器是接受函数返回新函数的函数。
Q2:2. 迭代器 Iterator —— 怎么理解?
A:迭代器像”自动翻页器”:iter() 拿迭代器、next() 逐个翻,翻完抛 StopIteration;for 循环本质就是不断 next(Iterator 迭代器)。
Q3:3. 生成器 Generator —— 怎么理解?
A:生成器像”会暂停的流水线”:yield 产出并保留状态,下次 next 从暂停处继续,最 Pythonic 的迭代器写法(Generator 生成器)。
Q4:5. 装饰器 Decorator —— 怎么理解?
A:装饰器像”给函数穿外套”:接受函数、包一层逻辑、返回新函数;@ 只是语法糖,等价 greet=my_decorator(greet)(Decorator 装饰器)。
Q5:三者关系速记 —— 怎么理解?
A:三者一条线:迭代器是底座,生成器用 yield 优雅实现它;闭包是机制,装饰器借闭包给函数加料(closure 闭包)。
Q6:核心速记主线有哪些?
-
迭代器:iter 返回自身、next 逐个取值,翻完 StopIteration
-
生成器:yield 暂停产出、状态保留,最 Pythonic 的迭代器
-
装饰器:接受函数返回新函数,@ 是语法糖
-
关系:迭代器→生成器,闭包→装饰器
口诀
A:迭代器翻页器,next 翻完停;
生成器会暂停,yield 留状态;
装饰器穿外套,函数包函数;
迭代器打底,闭包撑装饰。