Python-生成器(generator)

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

 

你可能感兴趣的:(Python)