【python】迭代器和生成器
作者:互联网
生成器和迭代器
概念
生成器:凭空生成元素,例如range()函数,之前返回完整的列表,现在返回类似生成器的对象
迭代器:从集合中取出元素,惰性获取数据项,按需一次获取一个
所有的生成器都是迭代器,因为生成器完全实现了迭代器接口。
所有的序列都可迭代
解释器需要迭代对象x时,会自动调用iter(x):
-
检查对象是否实现了
__iter__
方法,如果实现了就调用它,获取一个迭代器 -
如果没有实现
__iter__
方法,但是实现了__getitem__
方法,python会创建一个迭代器,尝试按顺序获取元素 -
如果尝试失败,则抛出TypeError异常
只要对象实现了__iter__
方法,则isinstance(x, abc.Iterable)
为True,因为abc.Iterable 类实现了 __subclasshook__
方法。但由于以上所说序列的特殊性,所以判断对象是否可迭代,最准确的方式是调用iter(x)
函数。
可迭代的对象与迭代器的区别
Python 从可迭代的对象中获取迭代器。
示例1
s = 'abc'
for char in s:
print(char)
如果没有for
,可以怎么写呢?
s = 'abc'
it = iter(s)
while True:
try:
print((next(it)))
except StopIteration:
del it
break
这样写呢?
s ='abc'
print(next(s))
# TypeError: 'str' object is not an iterator
结论:
不要在可迭代对象里实现next
方法,尝试把可迭代对象变成迭代器是错误的,也是常见的反模式。我们必须在对象的__iter__
方法中去新建一个独立的迭代器,在这个迭代器中去实现__next__
方法。可迭代的对象一定不能是自身的迭代器,不可以实现__next__
方法。
标准的迭代器接口有两个方法:
__next__
:返回下一个可用的元素,如果没有元素了,抛出StopIteration异常
__iter__
:返回self
实现迭代器
-
在
Iterable.__iter__
方法中返回一个 Iterator 实例。具体的 Iterator 类必须实现__next__
方法,返回单个元素,此外还要实现Iterator.__iter__
方法,返回实例本身。具体见示例14-4。即如果对象实现了能返回迭代器的__iter__
方法,那么对象是可迭代的对象,python从可迭代的对象中获取迭代器。 -
使用yield关键字创建生成器函数。生成器函数调用时会构建一个实现了迭代器的生成器对象。只要函数中有关键字yield,则该函数是生成器函数
-
def gen_AB():
print('start')
yield 'a'
print('end')
for i in gen_AB():
print(i)
# 注释掉函数中的yield,则会报错TypeError: 'NoneType' object is not iterable -
其它
-
-
使用
()
生成器表达式,()
只是一个语法糖,代替yield生成器函数来创建生成器,更节省内存-
def gen_AB():
print('start')
yield 'a'
print('end')
res1 = [x * 3 for x in gen_AB()]
for i in res1:
print('--->', i)
# start
# end
# ---> aaa
res2 = (x * 3 for x in gen_AB()) # res2 是一个生成器对象,只有 for 循环迭代 res2 时,gen_AB 函数的定义体才会真正执行
for i in res2:
print('--->', i)
# start
# ---> aaa
# end -
其它
-
-
使用现成的函数,比如要生成等差数列
-
class ArithmeticPregression:
def __init__(self, begin, step, end=None):
self.begin = begin
self.end = end
self.step = step
def __iter__(self): # 属于方法二
result = type(self.begin + self.step)(self.begin)
forever = self.end is None
index = 0
while forever or result < self.end:
yield result
index += 1
result = self.begin + self.step * index -
# 使用itertools.count和takewhile
import itertools
def aritprog_gen(begin, step, end=None):
first = type(begin + step)(begin)
ap_gen = itertools.count(first, step)
if end is not None:
ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
return ap_gen
# 用法
gen = itertools.count(1, .5)
print(next(gen)) # 1
print(next(gen)) # 1.5
gen = itertools.takewhile(lambda n: n < 3, itertools.count(1, .5))
print(list(gen)) # [1, 1.5, 2.0, 2.5]
-
标准库中的生成器函数整理
-
用于过滤的生成器函数
-
compress
-
dropwhile
-
filter(内置)
-
filterfalse
-
isslice
-
takewhile
-
-
用于映射的生成器函数
-
accumulate
-
enumerate(内置)
-
map(内置)
-
starmap
-
-
用于合并多个可迭代对象的生成器函数
-
chain
-
chain.from_iterable
-
product
-
zip(内置)
-
zip_longest
-
-
用于把输入的各个元素扩展成多个多个输出元素的生成器函数
-
combinations
-
combinations_with_replacement
-
count
-
cycle
-
permutations
-
repeat
-
-
用于重新排列元素的生成器函数
-
groupby
-
reversed(内置)
-
tee
-
可迭代的归约函数
-
all
-
# 一旦确定结果则立即停止迭代器
g = (n for n in [0, 0.0, 7, 8])
all(g)
print(next(g)) # 0.0 -
-
-
any
-
g = (n for n in [0, 0.0, 7, 8])
any(g)
print(next(g)) # 8 -
-
-
max
-
min
-
functools.reduce
-
sum
-
标签:__,迭代,python,self,生成器,print,gen 来源: https://www.cnblogs.com/xiaolongbao2021/p/16111040.html