python迭代器生成器
正文:
- 容器
- 迭代器
- 可迭代对象
- 生成器
容器:
容器就是存储某些元素的统称,特性:可以用in
或 not in
来判断一个元素存在/不存在于一个容器内。
str
、list
、tuple
、set
、dict
都可以通过 in
或 not in
来判断一个元素是否在存在/不存在这个实例中,所以这些类型都可以称作「容器」
print('x' in 'xyz') # 字符串 print(1 in [1, 2, 3]) # 列表 print(2 not in (1, 2, 3)) # 元组 print('x' not in {'a', 'b', 'c'}) # 集合 print('a' in {'a': 1, 'b': 2}) # 字典
之所以可以使用 in
或 not in
来判断「容器」是因为实现了 __contains__
方法。一个类只要实现了 __contains__
方法,那么它就是一个「容器」。
class A: def __init__(self): self.items = [1, 2] def __contains__(self, item): return item in self.items a = A() print(1 in a) # True print(3 in a) # False
容器另一个常用的功能是:输出容器内的所有元素。例如执行 for x in [1, 2, 3]
,(in关键字后面的必须是可迭代对象iterable),就可以迭代出容器内的所有元素。
迭代器:
对于for loop而言,有两个核心概念必不可少:可迭代对象(iterable)、迭代器(iterator)
可迭代对象iterable更像是一个数据保存者一个容器,它可以没有状态 可以不知道迭代器iterator数到哪了,但是它必须要产生一个迭代器iterator
迭代器(iterator)是一个表示数据流的对象,可以使用next函数不断的从这个对象里面获取新的数据,iterator必须要有__next__这个method,这个method保证它被next()作用的时候可以返回下一个iterable里面的值,iterator最核心的部分是要有这个__next__函数
几个常见可迭代对象:
lst = [1,3,5] for i in lst: print(i)
d = {'a':1,'b':2}
for i in d:
print(i)
with open('my.txt') as f:
for i in f:
print(i)
一个对象要想使用 for
的方式迭代出容器内的所有数据,需要实现以下 2 个方法:
__iter__
:这个方法返回对象本身,即self,让每个迭代器也是可迭代的
__next__
:这个方法每次返回迭代的值,在没有可迭代元素时,抛出StopIteration
异常
#!/usr/bin/python # -*- coding: UTF-8 -*- class NodeIter: # 迭代器iterator def __init__(self, node): self.curr_node = node # iterator class 核心部分要有__next__函数,每次调用这个函数的时候,两种情况,如果这个iterator到头了需要raise一个 # StopIteration,如果还有数据的话把这个数据return回去, def __next__(self): if self.curr_node is None: raise StopIteration node, self.curr_node = self.curr_node, self.curr_node.next return node def __iter__(self): return self class Node: # 可迭代对象iterable:凡是可以返回一个迭代器的对象,都称为可迭代对象 def __init__(self, name): self.name = name self.next = None def __iter__(self): # __iter__方法返回一个迭代器 return NodeIter(self) node1 = Node("node1") node2 = Node("node2") node3 = Node("node3") node1.next = node2 node2.next = node3 for node in node1: print(node.name)
其实在执行 for
loop循环时,实际执行流程是这样的:
for i in iterableA
会对iterableA进行一次iter()这么一个操作,相当于执行iter(terableA),实际而言,for loop首先做了一个从iterable里面拿到iterator的操作,在进行forloop之前这个iterable会先被取一个iter的值,然后这个for loop是根据这个iterator来进行操作的
- iterator每次迭代时会执行一次
__next__
方法,返回一个值,这就是iterator为啥要有__next__这个方法的原因,这个方法保证它被next()作用的时候可以返回下一个iterable里面的值 - 如果没有可迭代的数据,抛出
StopIteration
异常,for
会停止迭代
# for loop过程可以想象成下面这个样子
lst = [1,3,5] it = iter(lst) for i in it: # 实际并不是这样子,因为执行for loop操作的时候还会对这个it进行一次iter()这么一个操作 print(i)
从实现上来看,一个iterable,要么就有这个__iter__这个method,要不然它就需要是一个序列sequence,然后有__getitem__这个method,这两者都是为了保证它可以在iter()这个函数的作用下,返回一个iterator
可迭代对象
凡是可以返回一个「迭代器」的对象,都可以称之为「可迭代对象」。即__iter__
方法返回一个迭代器,那么这个对象就是「可迭代对象」。
上文中的class Node不是一个「迭代器」,因为它只了实现 __iter__
,没有实现 __next__,
由于class Node的 __iter__
返回了NodeIter的实例,而NodeIter是一个迭代器,所以Node的实例是一个「可迭代对象」,换句话说,Node把迭代细节交给了 NodeIter
生成器
「生成器」generator是一个特殊的「迭代器」,并且它也是一个「可迭代对象」
2 种方式可以创建一个生成器:
- 生成器表达式
- 生成器函数
生成器表达式创建生成器
g = (i for i in range(5)) # 创建生成器,类型是generator print(type(g)) # <class 'generator'> print(g) # 生成器就是一个迭代器 print(iter(g)) for i in g: # 生成器也是一个可迭代对象 print(i)
生成器函数创建生成器
在这里我们要区分什么是生成器函数、生成器对象,当函数定义里面有yield的这个关键词的时候,它就不会把这个函数当成一个普通函数来处理,python会给这个函数打上一个标签,然后说这是一个生成器函数,调用生成器函数,会生成一个生成器对象
def gen(num): # 生成器函数 while num > 0: yield num num -= 1 return # 在生成器函数里面,return等价于raise Stoplteration # g叫做生成器对象 g = gen(5) # 调用生成器函数不会返回值,而会返回一个生成器对象,保存到g里 print(g) # <generator object gen at 0x10bb46f50> print(type(g)) # <type 'generator'> # 生成器也可以使用next函数,用next将第一个拿出来 first = next(g) # 迭代这个生成器 for i in g: print(i)
生成器高级用法send
send就是在这个生成器yield之后,把这个yield的什么东西变成一个值,然后这个值还可以继续赋给这个生成器函数里面的其他变量,send函数只是给一个机制让你可以去和你的generator做沟通和交流,可以改变它的一些状态。如果yield num没有赋值给一个变量的时候,send任何东西包括send None跟用next就是一样的等价的
def gen(num): while num > 0: tmp = yield num # 在这个生成器yield之后,send可以理解为yield num进行了一次赋值,赋值成了send进来的这个值 if tmp is not None: num = tmp num -= 1 g = gen(5) first = next(g) # 等价于first = g.send(None),tmp=None直接跳到num-=1 print(f"first:{first}")
# num先被赋值成了10,然后又减了1,所以下一次yield出来是9 print(f"send:{g.send(10)}") for i in g: print(i)
参考学习:https://zhuanlan.zhihu.com/p/319402935
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」