Python 迭代器、生成器
for 过程中到底发生了什么?
for item in xxxx:
print(item)
- 检查该对象是否是可迭代对象
isinstance(obj,Iterable)
- 在第一步成立的前提下,调用iter函数得到obj对象的__iter__()方法的返回值
- iter()方法的返回值,是一个 迭代器
from collections.abc import Iterator,Iterable
class Mylist():
def __init__(self):
self.mylist = []
def add(self, item):
self.mylist.append(item)
self.myidx = 0
# 该对象是可迭代对象的基础是 对象里面有 __iter__()方法
def __iter__(self):
return self # 必须返回一个迭代器,即实现了__iter__和__next__的类
def __next__(self):
if self.myidx < len(self.mylist):
res = self.mylist[self.myidx]
self.myidx += 1
return res
else:
raise StopIteration
if __name__ == '__main__':
mylist = Mylist()
mylist.add(1)
mylist.add(2)
mylist.add(3)
print(isinstance(mylist, Iterable)) # 是否实现__iter__方法
print(isinstance(mylist, Iterator)) # 想要是一个迭代器,__iter__方法必须返回一个迭代器
# 而这个迭代器里面 必须实现__next__方法和__iter__方法
# 也就是说实现__iter__方法只能保证它是一个可迭代对象
# 而__next__方法在__iter__方法实现的前提下,使得对象成为 迭代器,且for 返回的值就是 next方法的返回值
for item in mylist:
print(item)
迭代器的应用
比如有个很大的数据,我们不想一次性都读入内存,内存不够,而是想要实现用一条,读一条。这里迭代器就会发挥很大的作用。
比如Pytorch的自定义数据集,就是利用了迭代器的原理。
生成器
如果一个函数中有yield语句,那这个函数就是一个生成器模版。
yield可以理解为会将程序暂停,然后返回yield后面的值,下次运行继续向后
所以说用yield 返回a 与range(1,1000)相比,它不会直接生成1-10000,而是用一个生成一个。
迭代器的核心就是,它保存的是生成数据的方式,不是直接生成的数据。生成器yield也是这样,可以让函数暂停执行,返回你想要的数据,再次运行的时候仍然保持上次的状态。
利用yield暂停程序的原理,可以实现并发多任务
两个函数交替执行,实现并发;
import time
def dancing():
while True:
print("dancing.....")
time.sleep(1)
yield
def singing():
while True:
print("singing.....")
time.sleep(1)
yield
def main():
d = dancing()
s = singing()
while True:
next(d)
next(s)
if __name__ == '__main__':
main()
License:
CC BY 4.0