文章目录
Iterator
Iterator 是Python 中用于 for in 的一种类型,如果要将对象实现为Iterator,该对象需要实现两个魔法方法__iter__
和__next__
。
__iter__
该方法在Iterator 初始化的时候被调用,用于返回一个可以迭代的对象,该对象需要实现__next__
方法。
__next__
该方法每次应该返回迭代的下一个值,并且在迭代结束时,抛出异常 StopIteration
表示迭代结束。
示例
如下的Fib类被实例化后,可以用于 for in 中迭代斐波纳切数列。
class Fib:
def __init__(self, lim: int = 100):
self.pre_num = 1
self.cur_num = 1
self.lim = lim
def __iter__(self):
return self
def __next__(self):
self.pre_num, self.cur_num = self.cur_num, self.cur_num + self.pre_num
if self.pre_num > self.lim:
raise StopIteration
return self.pre_num
fib = Fib()
for each in fib:
print(each)¡
Generator
Generator function
函数体内包含有 yield
关键字的函数将被视为 generator function,当它想要返回一个结果时,使用 yield
而不是 return
。此时,函数将会被Python Frame挂起,并将返回前的状态保存下来。等下一次该函数再被调用时,Frame将恢复挂起的状态并继续执行。示例如下:
def fib(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
Gernerator object
当有如下执行语句时,generator function 的返回值不是结果,而是一个generator 对象。
# "fib" implementation refers to above one.
f = fib(100)
for each in f:
print(each)
该对象和 Iterator 类似,可以用 for in
语句来进行迭代,结束也会抛出异常 StopIteration
表示迭代终止。
Generator expression
使用Generator 表达式可以生成一个匿名的Generator function,语法就是将列表推导式的中括号变为小括号。如下:
# Output: <generator object <genexpr> at 0x0000000002EBDAF8>
(x**2 for x in my_list)
不像列表推导式会直接返回一个列表,生成器表达式仍然遵循生成器的规则,每次 next 返回一个结果。该表达式还可以作为函数的传入参数,此时可以省去表达式两端的小括号,如下:
# Output: 146
sum(x**2 for x in my_list)
Generator优势
实现简洁
相较于Iterator,生成器的__iter__, __next__方法和 StopIteration 异常都由Python隐式地生成。
内存高效
普通的函数在返回一个序列前,需要将完整的序列保存到内存中。如果一个序列包含了大量的items,将会造成严重的内存占用。而生成器每次只产生一个item。
表示无限序列
无限的序列无法用容器存放,但可以用Generator来表示。
流水线
通过流水线可以获得更高的可读性和效率,例如:
with open('sells.log') as file:
pizza_col = (line[3] for line in file)
per_hour = (int(x) for x in pizza_col if x != 'N/A')
print("Total pizzas sold = ",sum(per_hour))
Reference
-
Python Generator - Programiz
-
Iterators in Python - GeeksforGeeks
-
Generators in Python - GeeksforGeeks