河南夏邑网站建设,wordpress分类栏目,手机影视网站制作,打码网站建设迭代器
Python 迭代器是一种对象#xff0c;它实现了迭代协议#xff0c;包括 __iter__() 和 __next__() 方法。迭代器可以让你在数据集中逐个访问元素#xff0c;而无需关心数据结构的底层实现。与列表或其他集合相比#xff0c;迭代器可以节省内存#xff0c;因…迭代器
Python 迭代器是一种对象它实现了迭代协议包括 __iter__() 和 __next__() 方法。迭代器可以让你在数据集中逐个访问元素而无需关心数据结构的底层实现。与列表或其他集合相比迭代器可以节省内存因为它们一次只生成一个元素。
迭代器的基本特点
懒加载迭代器不会一次性将所有数据加载到内存中而是根据需要生成元素。状态保持迭代器在迭代过程中会保持其状态可以从上次停止的地方继续迭代。可以遍历迭代器是可遍历的可以使用 for 循环等结构来进行遍历。 下面的代码可以看出迭代器在节省内存方面的作用。
import sys
import random# 生成 1-100的随机数的集合共1000个元素
numbers [random.randint(1, 100) for _ in range(1000)]
iterator iter(numbers)# 打印对象的内存大小
print(sys.getsizeof(numbers)) # 9016
print(sys.getsizeof(iterator)) # 48 迭代器的经典demo
# 创建一个简单的迭代器
class MyIterator:def __init__(self, limit):self.limit limitself.current 0def __iter__(self):return selfdef __next__(self):if self.current self.limit:self.current 1return self.currentelse:raise StopIteration# 使用迭代器
for num in MyIterator(5):print(num) 迭代器在读取大文件的经典应用
with open(users.csv, r) as file:for line in file:print(line.strip()) 逐行读取文件内容而不需要将整个文件加载到内存中。这种方法节省了内存资源特别是在处理非常大的文件时。
生成器
生成器是一种特殊类型的迭代器它允许你在函数中暂停执行并在以后继续。
使用 yield 的基本概念 生成器函数当一个函数包含yield语句时它不再是一个普通的函数而是一个生成器函数。当调用这个函数时它不会立即执行而是返回一个生成器对象。 状态保留每次调用生成器的__next__()方法或者使用next()函数时生成器函数会从上次执行的位置继续执行直到遇到下一个yield语句。在此时函数的执行状态包括局部变量会被保留。 迭代生成器可以被用于迭代像普通的列表或其他可迭代对象一样。使用for循环可以逐个获取生成器产生的值。
# 定义一个生成器函数
def read_users():with open(users.csv, r) as file:for line in file:yield line.strip()r1 read_users() # 定义一个生成器对象
r2 read_users() # 定义另一个生成器对象
print(next(r1))
print(next(r1))
print(next(r1))
print(next(r1))
print(next(r2))
print(next(r2))
print(next(r2))
print(next(r2))
局部变量保留的demo
list1 [a, b, c, d, e, f]def iterator():i 0for x in list1:yield do_something(i, x)i 1def do_something(i, x):print(i, x)r1 iterator() # 定义一个生成器对象
r2 iterator() # 定义另一个生成器对象
next(r1)
next(r1)
next(r1)
next(r1)
next(r2)
next(r2)
next(r2)
next(r2)
next(r2)
运行结果
0 a
1 b
2 c
3 d
0 a
1 b
2 c
3 d
4 e
更深入理解yield的“暂停”
函数每次遇到yield就暂停它并不在意yield时来自于循环、迭代或者是在函数体内重复定义的这意味着一个函数中可以有不止一个yield并且每次运行到yield时函数就暂停运行并保存中间结果和变量直到下一次next()后继续运行。
list1 [a, b, c, d, e, f]def iterator():for x in list1:yield print(x)yield print(x)yield print(x)yield print(x)r1 iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
next(r1)
next(r1)
next(r1)# 运行结果
# a
# a
# a
# a
# b
# b
可以将yield理解为一个中断标志 可以将yield理解为一个中断标志当生成器遇到 yield 语句时它会暂停执行并返回 yield 后面跟随的值或者函数。如果yield后面没有跟随内容那么它就仅仅是一次暂停标志而已。
list1 [a, b, c, d, e, f]def iterator():i 0for x in list1:print(loop, i)yieldi 1print(x)r1 iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
# 执行结果
# loop 0
# a
# loop 1
# b
# loop 2 yield的灵活运用
既然函数每次遇到yield就暂停它并不在意yield时来自于循环、迭代或者是在函数体内重复定义的而且可以将yield理解为一个中断标志那么我们也就可以生成一个不循环的函数通过yield达到步进执行的效果。
list1 [a, b, c, d, e, f]def iterator():i 0print(breakpoint, i)yieldi 1print(breakpoint, i)yieldi 1print(breakpoint, i)yieldi 1print(breakpoint, i)yieldi 1print(breakpoint, i)r1 iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
# 执行结果
# breakpoint 0
# breakpoint 1
# breakpoint 2注意可暂停和可迭代次数
要保证调用的次数不要大于可迭代次数或者可暂停次数否则就会报错。
def iterator():i 0print(breakpoint, i)i 1yieldprint(breakpoint, i)i 1yieldr1 iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
上面的例子定义了两个yield但是next调用了三次所以出错。
list1 [1, 2, 3]def iterator():for i in list1: # 遍历列表yield print(i)r1 iterator() # 定义一个生成器对象
next(r1)
next(r1)
next(r1)
next(r1)这个由于调用次数大于了列表的元素数量也会出错。
采取措施避免程序崩溃
1、使用try
def iterator():i 0print(breakpoint, i)i 1yieldprint(breakpoint, i)i 1yieldr1 iterator() # 定义一个生成器对象def next_do():try:next(r1)except StopIteration:print(No more items to yield)next_do()
next_do()
next_do()
next_do()list1 [1, 2, 3]def iterator():for i in list1: # 遍历列表yield print(i)r1 iterator() # 定义一个生成器对象def next_do():try:next(r1)except StopIteration:print(No more items to yield)next_do()
next_do()
next_do()
next_do()
next_do()# 运行结果
# 1
# 2
# 3
# No more items to yield
# No more items to yield2、指定next()的默认返回值参数如果指定了该参数并且迭代器没有更多的值可返回则返回该参数的值而不是引发 StopIteration 异常。
def iterator():i 0print(breakpoint, i)i 1yieldprint(breakpoint, i)i 1yielddef next_do():if next(r1, END): # 指定next()的默认返回值可以是任意非None值print(No more items to yield)r1 iterator() # 定义一个生成器对象next_do()
next_do()
next_do()
next_do()
next_do()# 运行结果
# breakpoint 0
# breakpoint 1
# No more items to yield
# No more items to yield
# No more items to yield
send()的用法
def generator_with_send():received yield # yield 语句会暂停生成器等待 send() 方法的调用并返回 yield 语句后面的值yield received # 输出接收到的值gen generator_with_send()next(gen) # 启动生成器
print(gen.send(this is send1)) # 通过 send() 方法向生成器发送数据 多次发送
def generator_with_send():received yield # 第一次调用 send 时暂停在此处yield received # 输出第一次接收到的值received yield # 再次暂停准备接收下一个值yield received # 输出第二次接收到的值received yield # 再次暂停准备接收下一个值yield received # 输出第三次接收到的值gen generator_with_send()next(gen) # 启动生成器
print(gen.send(this is send1)) # 发送数据
next(gen) # 继续执行准备接收下一个值
print(gen.send(this is send2)) # 发送数据
next(gen) # 继续执行准备接收下一个值
print(gen.send(this is send3)) # 发送数据# 输出结果为
# this is send1
# this is send2
# this is send3
OR:
def generator_with_send():received yield # 第一次调用 send 时暂停在此处received yield received # 每次重新接收 send() 发送的值received yield received # 每次重新接收 send() 发送的值received yield received # 每次重新接收 send() 发送的值gen generator_with_send()next(gen) # 启动生成器
print(gen.send(this is send1)) # 第一次发送 this is send1
print(gen.send(this is send2)) # 第二次发送 this is send2
print(gen.send(this is send3)) # 第三次发送 this is send3 OR:
def generator_with_send():received yield # 第一次调用 send 时暂停在此处while True:received yield received # 每次重新接收 send() 发送的值gen generator_with_send()next(gen) # 启动生成器
print(gen.send(this is send1)) # 第一次发送 this is send1
print(gen.send(this is send2)) # 第二次发送 this is send2
print(gen.send(this is send3)) # 第三次发送 this is send3close()的用法 close()方法用于关闭生成器关闭后如果尝试迭代或恢复执行生成器会引发 StopIteration 异常。 在生成器中close() 方法会触发 GeneratorExit 异常通过捕捉这个异常在生成器中进行必要的清理工作比如释放资源、关闭文件等。
def my_generator():try:while True:value yieldprint(fReceived: {value})except GeneratorExit:print(Generator is being closed.)gen my_generator()# 启动生成器
next(gen)# 发送一些值
gen.send(Hello)
gen.send(World)# 关闭生成器
gen.close()# 再次尝试发送值会引发 StopIteration 异常
try:gen.send(This will not work)
except StopIteration:print(Generator is closed and cannot receive values.)