4【python】:迭代器,生成器,装饰器

发布时间:2026/8/14 15:55:56
4【python】:迭代器,生成器,装饰器 1. 迭代器// C语言 int cards[] {1, 2, 3, 4}; for (int i 0; i 4; i) { printf(%d\n, cards[i]); }# Python cards [1, 2, 3, 4] for card in cards: print(card)_iter_的意思 我能被迭代在写 for card in cards 时Python会先调用cards 的 __iter__ 方法来确认这个列表是否支持迭代通俗说__iter__就像在问你能被一个一个取出来吗列表说能返回一个迭代器数字说不能报错① 字符串、列表、元组、字典、文件...都是可迭代对象迭代器一定也是可迭代对象② 迭代器对象从集合的第一个元素开始访问直到所有的元素被访问完结束。迭代器只能往前不会后退。_next_的意思 给我下一个当Python在循环时它会不断调用迭代器的 __next__ 方法每次调用都返回下一个元素通俗说__next__就像在说再给我下一个有元素 → 返回元素没有元素 → 说没了StopIterationStopIteration 的意思 没了当迭代器取完所有元素再调用 __next__ 时它会抛出 StopIteration 异常来告诉Python没东西了停止循环吧比如你在写上面那个card的python代码时Python内部执行了这个剧本# 第1步问列表你能被迭代吗 调用 cards.__iter__() it iter(cards) # 获取迭代器 # 第2步循环开始 while True: try: # 第3步问迭代器给我下一个 调用 it.__next__() card next(it) # 第4步拿到元素执行循环体 print(card) # 第5步迭代器说没了 跳出循环 except StopIteration: break2.生成器生成器到底是什么东西它是一个函数用def写的但这个函数里用yield代替了return调用时不执行只是制造了一个生成器对象next()才执行跑到yield就暂停把值返回状态自动保留再next()它从刚才停下来的地方继续干生成器就是一个可以暂停的函数暂停的时候还能返回一个值给你下次叫它的时候它接着干。 和普通函数的区别普通函数用 return你叫它它就从头到尾跑完跑完了给你一个结果里面的变量全没了生成器函数用 yield你叫它它不跑只是给你一个遥控器你按一下next()它跑一段就停给你一个值里面的变量全都留着下次按遥控器继续生成器就是迭代器只不过它是用 yield 写出来的迭代器。生成器只能遍历一次遍历完后就用完了第二次是空的。return在生成器里的作用是结束生成器附带的信息会放在异常里而不是作为正常返回值一个生成器函数里可以有多个yield但只能有一个return。return不是用来返回值的是用来彻底结束的。def 厨师(): yield 第一道菜 yield 第二道菜 yield 第三道菜 点菜 厨师() # 厨师站那不动没做菜 print(点菜) # 打印出来是个生成器对象 print(next(点菜)) # 厨师开始做做完第一道就停给你第一道菜 print(next(点菜)) # 厨师接着做做完第二道就停给你第二道菜 print(next(点菜)) # 厨师接着做做完第三道就停给你第三道菜 # print(next(点菜)) # 厨师说没菜了报 StopIteration3.装饰器在不修改原函数代码的前提下给函数增加新功能。装饰器 函数包装函数 不修改原代码扩展功能 语法本质是函数替换wrapper 才是真正执行的函数推荐使用 *args, **kwargs 提高通用性支持函数、类、甚至带参数的装饰器 第一步你本来有一个函数#假设你写了这样一个函数 def say_hello(): print(Hello!) #现在调用它 say_hello() # 输出Hello! 第二步你有了一个新需求你现在想让这个函数在执行前后各打印一行像这样Hello! 第三步最直接的办法但不推荐#你直接改原函数 def say_hello(): print() print(Hello!) print()这样确实能达到效果但问题是如果以后有 10 个函数都要加边框你要改 10 次。而且如果你想把边框改成-----你又要改 10 次。 第四步你想出一个办法你心想我能不能不修改原函数但调用它的时候自动加上边框#于是你写了一个包装函数 def add_border(func): def wrapper(): print() func() # ← 这里调用原函数 print() return wrapper这个add_border函数的作用是接收一个函数比如say_hello在内部定义一个新函数wrapperwrapper里先打印边框 → 调用原函数 → 再打印边框返回这个wrapper注意add_border没有修改say_hello它只是造了一个新函数wrapper这个新函数里包含了原函数 边框。 第五步你把原函数替换掉你现在有一个原函数say_hello和一个包装函数add_border。say_hello add_border(say_hello)这行代码在做什么右边的add_border(say_hello)把say_hello传给add_border返回wrapper左边的say_hello 把这个wrapper赋值给变量say_hello现在say_hello不再指向原来的函数了它指向wrapper 被装饰后原函数被替换了。但wrapper内部会调用原来的say_hello所以原来的功能还在只是多了边框。 第六步你现在调用say_hello()#现在再调用函数 say_hello() #因为 say_hello 现在指向 wrapper所以实际执行的是wrapper def wrapper(): print() 原来的 say_hello() # 打印 Hello! print() #输出 Hello! 第七步语法糖你觉得每次都要写say_hello add_border(say_hello)太麻烦了Python 提供了更简单的写法add_border def say_hello(): print(Hello!)这个add_border和say_hello add_border(say_hello)做的事情完全一样只是写法更简洁了。