生成器
生成器
生成器是一个函数,按照顺序返回一个或多个值。含有关键字yield的函数就是生成器。
def fib(n):
a = 0
b = 1
for i in range(n):
if not i:
yield 1
else:
a, b = b, a+b
yield b
for i in fib(5):
print(i)
fiby = fib(5)
for i in range(6): # next函数可以得到下一个值,当没有值可以返回时,引起StopIteration错误
print(next(fiby))
生成器之间的交互
生成器协议提供了一个额外的send方法,可以实现生成器的反向沟通。
yield语句实际上是一个表达式,可以用send方法赋值给yield表达式的结果
def fun():
var = yield 3
print(f"send({var})")
yield var
f = fun()
print(next(f)) # 3
print(f.send("a"))
# send(a)
# a
def square(n = 1):
while True:
var = yield n**2 # 默认情况下yield表达式的结果为None,当
# 调用send函数时,send的实参会赋值给var,从而影响生成器
if var:
n = var
else:
n+=1
sq = square()
print(next(sq)) # 1
print(next(sq)) # 4
print(sq.send(5)) # 25 , send把5赋值给var
print(next(sq)) # 36
print(next(sq)) # 49
def sq2(n=1):
while True:
res = yield n**2
n+=1
if res:
yield res**2
sq = sq2()
print(next(sq)) # 1
print(next(sq)) # 4
print(sq.send(5)) # 25 , send把5赋值给res
print(next(sq)) # 9
print(next(sq)) # 16
import inspect
import types
range_ = range(3)
zip_ = zip(['a','b'],[1,2])
dic = dict(zip_)
enumerate_ = enumerate(list("abc"))
map_ = map(int, ['1','2'])
for obj in [range_, zip_,enumerate_, map_, dic.keys(),dic.items(),dic.values()]:
print(obj, "is generator ?", isinstance(obj, types.GeneratorType))
print(obj, "is generator ?", inspect.isgenerator(obj))
# range(0, 3) is generator ? False
# range(0, 3) is generator ? False
# <zip object at 0x000001C8E84A3580> is generator ? False
# <zip object at 0x000001C8E84A3580> is generator ? False
# <enumerate object at 0x000001C8E84AB9C0> is generator ? False
# <enumerate object at 0x000001C8E84AB9C0> is generator ? False
# <map object at 0x000001C8E8375E20> is generator ? False
# <map object at 0x000001C8E8375E20> is generator ? False
# dict_keys(['a', 'b']) is generator ? False
# dict_keys(['a', 'b']) is generator ? False
# dict_items([('a', 1), ('b', 2)]) is generator ? False
# dict_items([('a', 1), ('b', 2)]) is generator ? False
# dict_values([1, 2]) is generator ? False
# dict_values([1, 2]) is generator ? False
yield from
生成器调用其他生成器
def f1():
yield 1
yield 2
def f2():
yield 'a'
yield 'b'
def func():
yield from f1()
yield from f2()
for i in func():
print(i)
单例斐波那契数列类
def signleton(cls):
instance = {}
def inner(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return inner
@signleton
class Fib:
def __init__(self) -> None:
self.numbers = []
def __iter__(self):
return self
def __next__(self):
if len(self.numbers)<2:
self.numbers.append(1)
else:
self.numbers.append(sum(self.numbers))
self.numbers.pop(0)
return self.numbers[-1]
def send(self, val):
pass
f1 = Fib()
f2 = Fib()
print(f1 is f2) # 单例
print(next(f1)) # 1
print(next(f1)) # 1
print(next(f1)) # 2
print(next(f1)) # 3
print(next(f1)) # 5
print(next(f2)) # 8