Python-迭代器、生成器与装饰器详解
1. 迭代器 (Iterator) - 可迭代的基石
- 可迭代对象(Iterable):能够被迭代遍历的对象,即可以通过循环(如 Python 的
for循环)逐个访问其内部元素的对象。- 本质:实现了 __iter__ (),调用 __iter__ ()应返回一个迭代器对象。
- 生成迭代器:iter(可迭代对象)
- 迭代器 (Iterator):执行遍历的工具,负责逐个返回元素(
__next__())并保存遍历状态。- 本质:只要实现了
__iter__()和__next__()这两个方法,任何对象都能叫迭代器。 - 访问全部元素:不断调用__next__(),直至返回StopIteration异常(迭代器是一次性的,重新迭代需要创建新的迭代器)
- 本质:只要实现了
- 让一个类成为迭代器:需要在类中实现两个方法__iter__()与 __next__()
- __iter__():必须返回一个迭代器对象,大多数情况下,直接返回
self即可(因为类本身就实现了__next__方法) - __next__(self):每次迭代循环时被调用,用于返回下一个值。(没有更多元素可以返回时,必须抛出
StopIteration异常)
- __iter__():必须返回一个迭代器对象,大多数情况下,直接返回
class Countdown: """一个从指定数字倒数到1的迭代器""" def __init__(self, start): # 初始化时,记录起始数字 self.start = start # 当前值从起始数字开始 self.current = start def __iter__(self): # 返回迭代器对象本身(self) # 在 for 循环开始时被调用 print(" (调用 __iter__,返回迭代器对象)") return self def __next__(self): # 每次迭代(如 for 循环的下一轮)时被调用 print(f" (调用 __next__,当前值: {self.current})") # 判断是否还有值可以返回 if self.current < 1: # 没有值了,必须抛出 StopIteration 异常 print(" (抛出 StopIteration,迭代结束)") raise StopIteration # 保存当前值,用于返回 value = self.current # 将当前值减1,为下一次调用做准备 self.current -= 1 # 返回本次迭代的值 return value # 使用示例: print("1. 创建一个从5开始的倒计时器对象") timer = Countdown(5) print("\n2. 在 for 循环中使用它:") #for循环过程:获取迭代器 -> 反复调用 __next__() for num in timer: print(f" => 得到数字: {num}") # 重要:迭代器是一次性的,如果再次尝试迭代,会立即结束 print("\n3. 尝试再次迭代(迭代器已耗尽):") for num in timer: print(num) # 这行不会执行,因为 __next__ 一开始就抛出 StopIteration else: print(" (没有输出任何数字,因为迭代器已经为空)")
2.生成器 (Generator) - 简洁的迭代器
生成器是一种更简洁的迭代器,创建生成器可以使用生成器函数(使用yield)或者生成器表达式(如(x**2 for x in range(10)))。
print(type(a)) #<class 'generator'> print(isinstance(a,Iterator)) #True,生成器是一种更简洁的迭代器
- 自动处理了
__iter__()和__next__()。 - 自动处理状态保持和StopIteration异常,代码量大大减少。
- 惰性求值、节省内存;适用于处理大型数据流或文件(调用1次__next__()只返回1个元素)。
- 【生成器函数-for循环访问】代码示例:
def countdown_gen(start): while start >= 1: yield start #yield会暂停函数状态,返回对应值 start -= 1 #for循环:先生成迭代器,再反复调用 __next__(),每次会从上次暂停处,继续往下执行 for num in countdown_gen(5): print(num)
- 【生成器函数-手动访问】代码示例:
def countdown_gen(start): while start >= 1: yield start start -= 1 a = countdown_gen(5) #调用生成器函数、返回一个迭代器对象 print(a.__next__()) #输出5 print(a.__next__()) #输出4 print(a.__next__()) #输出3
- 【生成器表达式】代码示例:
# 1. 列表推导式:一次性创建所有数据 print("=== 列表推导式 ===") list_comp = [x**2 for x in range(5)] # 使用方括号 [] print(f"列表推导式结果: {list_comp}") #[0, 1, 4, 9, 16] print(f"类型: {type(list_comp)}") # <class 'list'> print(f"占用内存大小(近似): {list_comp.__sizeof__()} 字节") #104 字节 # 2. 生成器表达式:创建一个生成器对象,不立即生成数据 print("\n=== 生成器表达式 ===") gen_exp = (x**2 for x in range(5)) # 使用圆括号 () print(f"生成器表达式结果: {gen_exp}") # <generator object <genexpr> at 0x0000018928981A40> print(f"类型: {type(gen_exp)}") # <class 'generator'> print(f"占用内存大小(近似): {gen_exp.__sizeof__()} 字节") # 64 字节 # 要获取生成器中的数据,需要遍历它 print("\n遍历生成器获取值:") for value in gen_exp: print(value, end=" ") # 输出: 0 1 4 9 16 # 注意:生成器是一次性的,再次遍历将没有输出 print("\n\n再次遍历生成器(已耗尽):") for value in gen_exp: print(value, end=" ") else: print("(没有输出任何值)")
3. 装饰器 (Decorator) - 修改行为的优雅方式
- 装饰器:一个修改函数或类的工具,本质上是一个高阶函数(接收函数作为参数,返回新函数)。
- 高阶函数:指能够接受函数作为参数或能够返回函数的函数。
- map(function, iterable):将指定的函数依次作用到可迭代对象(如列表)的每一个元素上,并返回一个迭代器
- filter(function, iterable):根据指定的函数(判断函数)对可迭代对象的元素进行过滤,保留返回值为
True的元素,并返回一个迭代器。
- 闭包:一个函数内部再定义一个函数(内层函数可以访问外层函数的变量,但外层函数不能访问内层函数的变量。)
- 作用:数据隐藏与封装
- 关系:装饰器是闭包在修改函数行为时的一个经典应用。
# 1. 定义外层函数 def outer_function(message): # 2. 定义并返回内层函数(闭包) def inner_function(): # 内层函数使用了外层函数的变量 message print(f"记忆中的消息是:{message}") #返回内层函数 return inner_function # 3. 创建两个不同的闭包实例 hello_closure = outer_function("你好!") bye_closure = outer_function("再见!") # 4. 调用闭包 hello_closure() # 输出:记忆中的消息是:你好! bye_closure() # 输出:记忆中的消息是:再见!
- 最简单的装饰器:打印出被装饰函数的执行耗时。
import time # 1. 定义装饰器(本质上是一个接收函数、返回新函数的高阶函数) def timer(func): # 2. 定义包装函数(闭包),它接收任意参数 def wrapper(*args, **kwargs): start_time = time.time() # 执行前记录开始时间 result = func(*args, **kwargs) # 执行被装饰的原始函数 end_time = time.time() # 执行后记录结束时间 print(f"函数 {func.__name__} 执行耗时: {end_time - start_time:.6f} 秒") return result # 返回原函数的执行结果 return wrapper # 3. 使用装饰器语法糖 @timer @timer def slow_function(): time.sleep(1) # 模拟一个耗时操作 return "执行完毕" # 4. 调用函数 print(slow_function()) # 函数 slow_function 执行耗时: 1.006022 秒 # 执行完毕
- 带参数的装饰器
# 1. 定义带参数的装饰器(装饰器工厂),times接收传入的参数 def repeat(times): """ 装饰器工厂:接收重复次数,返回真正的装饰器 """ print(f"进入装饰器工厂,要重复执行 {times} 次") # 2. 定义真正的装饰器,func接受传入的函数 def decorator(func): print(f" 进入装饰器,正在装饰函数 {func.__name__}") # 3. 定义包装函数(闭包),被调用时才执行包装函数 def wrapper(*args, **kwargs): last_result = None for i in range(times): print(f" 第 {i+1} 次执行 {func.__name__}") last_result = func(*args, **kwargs) return last_result |
PS C:\Users\wei.feng\Desktop\opt\server_test_platform> python .\debug.py --- 开始调用函数 say_hello --- 函数名: wrapper 1、say_hello()的__name__会被包装函数替换 2、包装函数为wrapper(),say_hello()的__name__为wrapper 3、保留被装饰函数的元信息:functools.wraps |
- 使用@functools.wraps(func)保留原函数的元信息(包括
__name__、__doc__、__module__等属性)
import functools # ---------- 1. 定义一个加 @wraps 的装饰器 ---------- def timer_with_wraps(func): @functools.wraps(func) # 关键行 def wrapper(*args, **kwargs): """这是 wrapper 的文档""" result = func(*args, **kwargs) return result return wrapper @timer_with_wraps def say_hello_with(name): """原函数:say_hello_with 的文档""" print(f"Hello, {name}!") print("\n2. 加上 @wraps 的装饰器结果:") print(f" 函数名: {say_hello_with.__name__}") # 函数名: say_hello_with print(f" 文档字符串: {say_hello_with.__doc__}") # 文档字符串: 原函数:say_hello_with 的文档
- 应用场景:日志、计时、校验、缓存等
本文来自博客园,作者:Fēngwèi,转载请注明原文链接:https://www.cnblogs.com/fengwei-blogs/p/21178911

浙公网安备 33010602011771号