生成器的两个特点:
1.惰性机制
2.生成器,在被调用之前,只是代表着一段没有被执行过的代码

一个有意思的python面试题,是下面的这个样子

def add(a,b):                     #普通求和函数
    return a + b
def test():                       #生成器函数
    for r in range(4):
        yield r
g=test()
for n in [2,10]:
    g=(add(n,i) for i in g)
print(list(g))

第一步分解

代码块注释如下(还是上面的内容,只是注释加多了)

def add(a,b):                     #普通求和函数
    return a + b
def test():                       #生成器函数
    for r in range(4):
        yield r
g=test()                          #获取生成器对象,后面的操作都指向这个对象,这和直接执行fun()函数销效果是不一样的
for n in [2,10]:                  #因为前面已经定义了生成器g,这个for循环的代码块等于是重新定义了变量g,
    g=(add(n,i) for i in g)       #重新定义的这个变量g也是一个生成器,使用推导式定义的生成器
print(list(g))                    #list自带for方法,所以list(g)会一次性把上面列表生成器的值拿完

第二步分解

代码简化(对上面的代码做了简化,但是都是等效的,主要是对for循环做了简化)

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def add(a,b):            #普通求和函数
    return a + b
def test():              #生成器函数
    for r in range(4):
        yield r
g=test()
n=2                      #这一行到下一步后,就没有了,我开始没理解。为什么就可以省略了?答案是当n=2时,只是生成了一个生成器,而并没有执行括号里面的代码,因为这时,没有人去调用
                         #这个生成器,所以这时的g只是代表着一段代码:(add(n,i) for i in g)。

g=(add(n,i) for i in g)
n=10
g=(add(n,i) for i in g)
print(list(g))

第三步分解

代码简化(对上面的代码做了简化,但是都是等效的,主要是对n重新赋值的过程做了简化)

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def add(a,b):            
    return a + b
def test():             
    for r in range(4):
        yield r
g=test()
n=10                                  #和上面的代码做比较,n重新赋值了两次,第二次已经把一次的赋值覆盖掉了,但是g因为前面做过定义,需要带入。
                                      #因为n=2时,没有执行括号里面的代码,所以,走到了n=10。但是,这时括号里面的代码还是没有执行,这个时候的g也不过是
                                      #一段代码:(add(n,i) for i in g)。而且,这时的n已经被重新赋值了,n=10.已经在内存中存在了。

g=(add(n,i) for i in (add(n,i) for i in g))#这里最外层括号里的g,是n=2时的生成器,第二步已经说过,那时的g只不过是一段代码,所以直接带过来就好了。
print(list(g))

第四步分解

代码简化(对上面的代码做了简化,但是都是等效的,带入数字10)

def add(a,b):            

    return a + b

def test():             
    for r in range(4):
        yield r
g=test()
                                 
g=(add(10,i) for i in (add(10,i) for i in g))
print(list(g))#走到这里时,因为list中有__next__(),所以开始跟生成器要值了,生成器开始循环起来。
#因为for循环自带__next__方法,所以for循环作用于生成器的时候也是一次性遍历完的,并不需要单独的在一个一个执行next
#分别带入i值0,1,2,3,可以生成g的一个生成器结果,再通过list(g)一次性拿完