1.定义:边循环边计算的机制,是一种特殊类型的迭代器,所以也会有__iter__和__next__方法,会在遍历过程中单独读取某一行的数据到内存
2.调用方式:
(1)for循环,for循环的本质就是调用了__iter__和__next__方法进行了迭代
(2)调用__next__()方法
(3)调用send方法
(4)数据类型强制转换,比如使用list()强制转换
3.两种实现方式:
(1)列表推导式外层的方括号改成圆括号
l1=[x*x for x in range(5)]
l2=(x*x for x in range(5))
print(type(l1)) #
print(type(l2)) #
print(l1) #[0, 1, 4, 9, 16]
print(l2) # at 0x032EED48>
print(list(l2)) #[0, 1, 4, 9, 16]
print(list(l2)) #[]--这是由于前面已经取完了
(2)yield关键字
#yield关键字
def my_print1(n):
for i in range(n):
yield i
print(my_print1(5)) #
print(list(my_print1(5))) #[0, 1, 2, 3, 4]
#与普通函数的区别:
def my_print2(n):
for i in range(n):
print(i)
print(my_print2(5))
#运行结果:
# 0
# 1
# 2
# 3
# 4
# None
用yield关键字就生成了生成器,可以用__next__()或for循环将数据取出;当函数执行到yield i 的时候,函数会把 i 的数值抛出来,我们用for循环遍历的时候获取了yield 后面的值,然后函数就会暂停,等待下一次遍历的时候,函数从yield继续向下执行,直到遇到yield的时候又返回了 i 的值,然后函数再暂停,等待下一次唤醒,这个循环一直做,到函数结束的时候
3.yield from关键字,解决了yield嵌套循环的问题
def chain1(*iter):
for it in iter:
for i in it:
yield i
print(list(chain1("abc",range(5)))) #['a', 'b', 'c', 0, 1, 2, 3, 4]
def chain2(*iter):
for i in iter:
yield from i
print(list(chain2("abc",range(5)))) #['a', 'b', 'c', 0, 1, 2, 3, 4]
4.看个经典的例子
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g=test()
list1=[1,10]
for n in list1:
print("n: ",n)
g=(add(n,i) for i in g) #此也为生成器
print(list(g))
# -----------------------
#运行结果:
# n: 1
# n: 10
#[20, 21, 22, 23]
#来个对比:
def add1(n,i):
return n+i
def test1():
for i in range(4):
yield i
g=test1()
list1=[1,10]
for n in list1:
print("n: ",n)
g=[add1(n,i) for i in g]
print(g)
# -----------------------
#运行结果:
# n: 1
# n: 10
#[11, 12, 13, 14]
分析:
第1个函数add实现简单的加法运算;
第2个函数test是生成器函数,调用它会返回一个生成器;
只要没有通过第2点的4种方法进行迭代,那么生成器就没有进行运算,所以在上面的for循环中无论是n=1时还是n=10时,生成器 g 都没有参与运算;
当n = 1时,g=(add(n,i) for i in g),这个表达式的结果 g 就是一个表达式,没有进行运算,g的值就是一个表达式(add(n,i) for i in g),括号里面的g实际上是test(),所以g = (add(n,i) for i in test()),仅此而已 ;
当n = 10时,g=(add(n,i) for i in g),把n=1时的 g 的结果带入进去就是g=(add(n,i) for i in (add(n,i) for i in test()))
当整段代码执行到print(list(g))语句之前,g的值就是一段代码,或者可以称之为算法,没有进行任何运算,里面的n就是n,g就是g,
不过此时因为代码是按照流程执行的,并且for循环已经执行完毕,所以n的值等于10,把前面的n=1的值覆盖,
当执行print(list(g))语句时,生成器才开始输出数据,此时执行最后一个g的赋值语句:
g=(add(n,i) for i in (add(n,i) for i in test()))
这时 n 的值等于10(因为代码是按照流程执行的,for循环已经执行完了,取了10,n的最终结果就是10),其中后面的(add(n,i) for i in test())这段代码的结果依然是个生成器,迭代后应为[10,11,12,13],所以最终的结果可以理解成:(add(n,i) for i in [10,11,12,13]),所以最终结果为:20,21,22,23