当前位置: 首页 > news >正文

10.Python 迭代器、生成器与装饰器 深度解析

Python 迭代器、生成器与装饰器 深度解析

目录

  1. 迭代器
    • 1.1 可迭代对象与迭代器协议
    • 1.2 手动实现迭代器
    • 1.3itertools模块掠影
  2. 生成器
    • 2.1 生成器函数与yield
    • 2.2 生成器表达式
    • 2.3yield from委托
    • 2.4 生成器的高级特性:sendthrowclose
  3. 装饰器
    • 3.1 高阶函数与闭包回顾
    • 3.2 装饰器原理与@语法
    • 3.3 保留元数据:functools.wraps
    • 3.4 带参数的装饰器
    • 3.5 类装饰器
    • 3.6 多个装饰器的叠加顺序
    • 3.7 实战示例:日志、计时、权限检查
  4. 总结与最佳实践

1. 迭代器

1.1 可迭代对象与迭代器协议

在 Python 中,可以用for循环遍历的对象都称为可迭代对象(Iterable),如列表、元组、字典、集合、字符串、文件等。可迭代对象的内部实现了__iter__方法,该方法返回一个迭代器(Iterator)。

迭代器是实现了__next__方法的对象,每次调用返回下一个元素,当元素耗尽时抛出StopIteration异常。迭代器本身也必须实现__iter__方法(通常返回自身),所以迭代器也是可迭代对象。

# 查看可迭代对象与迭代器lst=[1,2,3]it=iter(lst)# 调用 __iter__,返回列表迭代器print(type(it))# <class 'list_iterator'>print(next(it))# 1print(next(it))# 2print(next(it))# 3# next(it) → StopIteration

for循环等价于以下过程:

it=iter(iterable)whileTrue:try:item=next(it)exceptStopIteration:break# 处理 item

1.2 手动实现迭代器

我们可以自定义可迭代的类,通过实现__iter____next__来控制迭代逻辑。

classCountdown:"""从 start 倒数到 1 的迭代器"""def__init__(self,start):self.current=startdef__iter__(self):returnselfdef__next__(self):ifself.current<1:raiseStopIteration num=self.current self.current-=1returnnumforninCountdown(3):print(n,end=' ')# 3 2 1

若要创建不可重复迭代的迭代器,可以像上面那样让__iter__返回self。若希望每次iter()调用都能生成新的迭代器(可重复遍历),则需要分离“可迭代对象”和“迭代器”:

classFibonacci:"""生成指定个数的斐波那契数"""def__init__(self,max_count):self.max=max_countdef__iter__(self):# 返回新的迭代器实例returnFibIterator(self.max)classFibIterator:def__init__(self,max_count):self.max=max_count self.a,self.b=0,1self.count=0def__iter__(self):returnselfdef__next__(self):ifself.count>=self.max:raiseStopIteration val=self.a self.a,self.b=self.b,self.a+self.b self.count+=1returnvalforninFibonacci(5):print(n)# 0, 1, 1, 2, 3

1.3itertools模块掠影

itertools是内置的高效迭代器工具集,值得一览:

importitertools# 无限迭代器c=itertools.count(10,2)# 10, 12, 14, ...# cy = itertools.cycle('AB') # A B A B ...# rp = itertools.repeat(5, 3) # 5 5 5# 排列组合forpinitertools.permutations('AB',2):# ('A','B'), ('B','A')passforcinitertools.combinations('ABC',2):# ('A','B'), ('A','C'), ('B','C')# 链式与压缩joined=itertools.chain([1,2],[3,4])# 1 2 3 4

2. 生成器

2.1 生成器函数与yield

生成器是一种用函数语法实现的迭代器。在函数内部使用yield关键字,该函数就变成了生成器函数,调用它不会执行函数体,而是返回一个生成器对象。

每次对生成器调用next()时,函数会执行到下一个yield语句并暂停,返回值传回调用者。下一次再调用next()时,从上次暂停处继续执行,直到函数结束触发StopIteration

defsimple_gen():print("开始")yield1print("继续")yield2print("结束")g=simple_gen()print(next(g))# 开始 \n 1print(next(g))# 继续 \n 2# next(g) → 结束 \n StopIteration

生成器特适合处理大数据流,因为它是惰性求值的,需要时才产生下一个值,内存占用极小。

defread_large_file(file_path):withopen(file_path)asf:forlineinf:yieldline.strip()# 永远不会将整个文件加载到内存forlineinread_large_file("giant.txt"):process(line)

2.2 生成器表达式

与列表推导式类似,但使用圆括号,产生一个生成器对象而不是一次性列表。适用于无需存储全部结果的情况。

squares=(x**2forxinrange(1000000))print(next(squares))# 0print(next(squares))# 1# 作为函数参数时可以省略一层括号total=sum(x**2forxinrange(1000000))

2.3yield from委托

yield from语法允许将一个生成器的所有值委托给另一个生成器,极大简化嵌套生成器的编写。

defflatten(items):foriteminitems:ifisinstance(item,(list,tuple)):yieldfromflatten(item)else:yielditem nested=[1,[2,[3,4],5],6]print(list(flatten(nested)))# [1, 2, 3, 4, 5, 6]

2.4 生成器的高级特性:sendthrowclose

生成器不仅可以生产数据,还可以通过send()接收外部传入的值,实现协程式的双向通信。

defecho():whileTrue:received=yieldprint(f"收到:{received}")g=echo()next(g)# 预激活生成器(推进至第一个 yield)g.send("Hello")# 收到: Hellog.send("World")# 收到: World
  • throw(type, value, traceback):在生成器暂停处抛出一个异常。
  • close():在生成器暂停处抛出GeneratorExit异常,用于终止生成器。
defcontrolled():try:whileTrue:yieldexceptGeneratorExit:print("生成器已关闭")g=controlled()next(g)g.close()# 生成器已关闭

这些高级特性是早期asyncio的基础,尽管如今异步编程主要使用async/await,理解它们仍有助于深入 Python 的运行模型。


3. 装饰器

3.1 高阶函数与闭包回顾

装饰器是高阶函数的典型应用:接受一个函数作为参数,并返回一个新函数。闭包特性使得内部函数可以捕获外部函数的变量。

defouter(x):definner(y):returnx+yreturninner add_five=outer(5)print(add_five(3))# 8

3.2 装饰器原理与@语法

装饰器本质上是一个接受函数并返回增强版函数的可调用对象。@decorator语法只是把目标函数传入装饰器并赋值的简写。

defuppercase(func):defwrapper(*args,**kwargs):result=func(*args,**kwargs)ifisinstance(result,str):returnresult.upper()returnresultreturnwrapper@uppercasedefgreet(name):returnf"hello,{name}"print(greet("Alice"))# HELLO, ALICE# 等价于: greet = uppercase(greet)

装饰器可以在函数之前或之后插入额外逻辑,也可以修改输入参数和返回值。

3.3 保留元数据:functools.wraps

直接返回wrapper会丢失原函数的名称、文档字符串、参数列表等元数据。使用functools.wraps可以将这些属性复制到wrapper上。

fromfunctoolsimportwrapsdeftimer(func):@wraps(func)defwrapper(*args,**kwargs):importtime start=time.time()result=func(*args,**kwargs)end=time.time()print(f"{func.__name__}执行时间:{end-start:.4f}s")returnresultreturnwrapper@timerdefslow_add(a,b):"""返回两数之和(缓慢版)"""importtime time.sleep(0.5)returna+bprint(slow_add.__name__)# slow_add (若不使用 wraps 则是 wrapper)print(slow_add.__doc__)# 返回两数之和(缓慢版)help(slow_add)

3.4 带参数的装饰器

如果装饰器本身需要参数(比如重复次数),则需要再包装一层装饰器工厂:外层函数接受配置参数,返回真正的装饰器。

defrepeat(times):defdecorator(func):@wraps(func)defwrapper(*args,**kwargs):for_inrange(times):result=func(*args,**kwargs)returnresultreturnwrapperreturndecorator@repeat(3)defsay_hello():print("Hello!")say_hello()# 打印 3 次 Hello!

@repeat(3)首先调用repeat(3)返回decorator,然后decorator(say_hello)返回wrapper

3.5 类装饰器

类也可以作为装饰器,只要实现了__call__方法。类装饰器在需要维护状态时更自然。

classCountCalls:def__init__(self,func):self.func=func self.count=0def__call__(self,*args,**kwargs):self.count+=1print(f"{self.func.__name__}已被调用{self.count}次")returnself.func(*args,**kwargs)@CountCallsdefhello():print("Hello")hello()# hello 已被调用 1 次 \n Hellohello()# hello 已被调用 2 次 \n Hello

带参数的类装饰器同样可以通过__init__接收配置参数,在__call__内根据参数创建并返回一个wrapper函数。

3.6 多个装饰器的叠加顺序

多个装饰器可以从下往上依次应用(等价于从里往外调用)。

@timer@uppercasedefgreet(name):returnf"hello,{name}"# 等价于: greet = timer(uppercase(greet))

调用greet("Alice")的流程:

  1. uppercasewrapper首先执行原greet,将返回值转为大写。
  2. 然后timerwrapper测量整体耗时。

装饰器顺序会影响行为,务必理清执行次序。

3.7 实战示例:日志、计时、权限检查

日志装饰器

deflog_function_call(func):@wraps(func)defwrapper(*args,**kwargs):print(f"[LOG] 调用{func.__name__}, 参数:{args},{kwargs}")result=func(*args,**kwargs)print(f"[LOG]{func.__name__}返回:{result}")returnresultreturnwrapper@log_function_calldefadd(a,b):returna+b add(3,5)

权限检查装饰器

defrequire_admin(func):@wraps(func)defwrapper(user,*args,**kwargs):ifuser.get("role")!="admin":raisePermissionError("需要管理员权限")returnfunc(user,*args,**kwargs)returnwrapper@require_admindefdelete_user(user,user_id):returnf"用户{user_id}已删除"admin={"name":"Alice","role":"admin"}guest={"name":"Bob","role":"guest"}print(delete_user(admin,42))# 正常# delete_user(guest, 42) # 抛出 PermissionError

缓存装饰器

fromfunctoolsimportlru_cache@lru_cache(maxsize=128)deffibonacci(n):ifn<2:returnnreturnfibonacci(n-1)+fibonacci(n-2)print(fibonacci(100))# 瞬间完成

@functools.lru_cache是标准库提供的内存缓存装饰器,用于优化重复计算的递归函数。


4. 总结与最佳实践

  • 迭代器是 Python 循环机制的核心,掌握__iter____next__协议可以创建自定义可迭代对象。
  • 生成器通过yield提供了一种简洁的迭代器实现方式,惰性求值的特点特别适合处理大数据流。使用yield from能简化子生成器的委托。
  • 装饰器本质上是对高阶函数和闭包的运用。它们能在不修改原函数代码的情况下添加切面功能,是 Python 最强大的元编程工具之一。
  • 编写装饰器时务必使用@wraps保留原始函数的元数据,否则调试和文档生成都会受影响。
  • 对于带参数的装饰器,牢记三层函数结构:外层接收配置参数,中层接收原函数,内层是实际的包装逻辑。
  • 当需要维护调用状态(如计数器)时,类装饰器可能更直观。
  • 善用标准库中的装饰器,如@property@staticmethod@classmethod@functools.lru_cache等,它们已经为常见任务提供了最优方案。
http://www.jsqmd.com/news/863477/

相关文章:

  • 3分钟快速上手SketchUp STL插件:终极3D打印模型转换完整指南
  • [MAF的Agent管道详解-04]如何让LLM按照要求的结构输出数据?
  • 浏览器资源嗅探革命:猫抓扩展如何重新定义在线媒体捕获体验
  • 如何快速安装BetterNCM:终极网易云音乐插件管理指南
  • 深度解析Unity游戏实时翻译插件:XUnity.AutoTranslator的5大实战应用场景与架构设计
  • 大学买不到GPU怪我?黄仁勋斯坦福现场火力全开:是你们体制的错!
  • Sub2API + CCSwitch 实现 Codex 反向代理:多账号流量分发实战(解决codex手机号验证)可以润色吗
  • 【紧急更新】Midjourney v6.1金属纹理算法变更预警:3个必须重训的材质参数阈值,错过将导致PBR贴图链断裂
  • 武安市建龙废钢基地物资:峰峰矿专业的废钢回收公司推荐几家 - LYL仔仔
  • 2026年国内矿粉球团粘合剂头部厂家实力排行 - 奔跑123
  • 3步彻底解决Windows右键菜单卡顿:ContextMenuManager终极优化指南
  • 抖音无水印批量下载终极指南:douyin-downloader免费神器
  • 5分钟搭建个人游戏云:Sunshine跨平台串流服务器完全指南
  • 2026年全球优质筋膜枪选购指南:轻松找到你的专属按摩神器 - 博客万
  • G-Helper:华硕笔记本的轻量级性能管家,让你的电脑重获新生
  • N_m3u8DL-CLI-SimpleG:让M3U8视频下载变得如此简单的终极图形界面工具
  • 2026论文降AI率工具谁是性价比之王?早标网最低1.0元/千字性价比拉满 - 全维度降AI
  • MelonLoader终极指南:解锁Unity游戏无限可能的5个核心步骤
  • 2026年软考知识点—计算机等级考试—软件设计师考前备忘录—东方仙盟
  • 三步掌握AMD Ryzen处理器终极调优:SMUDebugTool完整使用指南
  • 2026港口码头监管低空平台建设指南:全域数字底座如何赋能安全高效运行 - 品牌2025
  • 【测试】一文读懂软件测试:新手真正需要的测试认知
  • Sunshine游戏串流终极方案:打造你的私人云游戏服务器
  • G-Helper:3步快速配置指南,释放华硕笔记本的真正潜能
  • 中兴光猫终极解锁指南:一键开启工厂模式与永久Telnet的完整解决方案
  • 2026年长春黄金回收避坑指南——福昌夏等六大机构实测对比 - 黄金上门回收
  • 高效掌握外语词汇:ToastFish桌面单词记忆工具完整指南
  • 鸣潮自动化助手:5步轻松实现后台智能战斗与资源收集
  • 2026年成都有哪些值得信赖的AI搜索优化公司? - 品牌推荐官方
  • 路由双雄对决:静态 vs 动态,从原理到实战的终极指南(万字长文)