Python生成器:理解执行的顺序

时间:2014-03-14 17:31:37

标签: python generator

 21 def power(values):
 22     print "power", values
 23     for value in values:
 24         print 'powering %s' % value
 25         yield value
 26
 27 def adder(values):
 28     print "adder", values
 29     for value in values:
 30         print 'adding to %s' % value
 31         if value % 2 ==0:
 32             yield value + 3
 33         else:
 34             yield value + 2
 35
 36 elements = [1, 4, 7, 9, 12, 19]
 37 res = adder(power(elements))
 38 print res.next()
 39 print res.next()
 40 print res.next()
 41 print res.next()

输出:

adder <generator object power at 0x7fb6b9ee7910>          <--- is this the stdout flush matter?
power [1, 4, 7, 9, 12, 19]
powering 1
adding to 1
3
powering 4
adding to 4
7
powering 7
adding to 7
9
powering 9
adding to 9
11

我想了解上面的代码。
1)为什么加法器在通电之前打印[1,4,7,9,12,19]?

2)加法器不是迭代通过元素而是迭代通过发电机,正确吗?

3)确认我对(1)的想法。所以加法器首先被调用然后在加法器的for value in values中,它是咨询发电机,因此,驱动打印线被触发,然后加法器打印线被触发?

4)如果是这样,为什么每次都不会调用print语句power [1, 4, 7, 9, 12, 19]powering <$> print语句?

3 个答案:

答案 0 :(得分:3)

生成器内的代码在调用next之前不会运行:

def gen():
    print "called"
    yield 3.14

g = gen()  # nothing is printed
g.next()  # print "called" and return 3.14

for循环正在执行下一步调用的工作,在您的代码中,这是在打印加法器后发生的:

g = gen()

print 'adder'  # prints adder

for i in g: # prints called (as inside generator, *before* yields)
    print i  # prints 3.14

答案 1 :(得分:3)

生成器函数在生成器上第一次调用__next__之前不会开始执行。例如:

>>> def gen():
...     print 'starting execution'
...     for i in range(10): yield i
...
>>> itr = gen()
>>> next(itr)
starting execution
0

所以回答你的第一个问题,&#34;为什么加法器在电源之前被打印&#34;,当你adder(power(elements))时,首先创建了生成器power(elements),但执行了该生成器直到for value in values内的adder()的第一次迭代才会开始。

答案 2 :(得分:3)

  1. power有一个yield返回,这使其成为generator。函数本身的代码仅在调用next()时执行。
  2. 正确。 adder依赖于生成器,并且没有关于正在迭代的数据的信息。 (如大小)
  3. 再次纠正
  4. yield是一条特别的指令。它不会从生成器函数(power)返回。相反,它提供一个值,暂停执行,直到下一次调用next()。此时,执行将在循环内的同一点恢复。
  5. 修改

    yield停止点的插图:

    def gene():
        print 'first!'
        yield 1
        print 'second!'
        yield 2
    
    g = gene()
    g.next()
    # first!
    # 1
    g.next()
    # second!
    # 2
    

    如您所见,生成器在yield指令后完全中断,准备执行下一个