2014-10-01 74 views
2

我想了解函数和生成器之间的区别,并使用下面的代码来实现该目的。但是,我不明白产出。Python中的生成器和函数之间的区别

class GeneratorsSample(object): 

    def DoReturn(self): 
     counter, maxCounter = 0, 5 
     listResults = [] 
     while counter < maxCounter: 
      print "tic" 
      listResults.append(counter*2) 
      counter += 1 
     return listResults 

    def DoYield(self): 
     counter, maxCounter = 0, 5 
     listResults = [] 
     while counter < maxCounter: 
      print "tic" 
      listResults.append(counter*2) 
      yield listResults #to return the entire list 
      #yield listResults[counter] #you can only return one item at a time 
      counter += 1 
     return 


generatorSample = GeneratorsSample() 

我不明白为什么,为DoReturn()输出是从的DoYield()不同。例如,

returnResults = generatorSample.DoReturn() 
for r in returnResults: 
    print "toc", r 

输出:

tic 
tic 
tic 
tic 
tic 
toc 0 
toc 2 
toc 4 
toc 6 
toc 8 

而且,

yieldResults = generatorSample.DoYield() 
for r in yieldResults:  
    print "toc", r 

输出:

tic 
toc [0] 
tic 
toc [0, 2] 
tic 
toc [0, 2, 4] 
tic 
toc [0, 2, 4, 6] 
tic 
toc [0, 2, 4, 6, 8] 
+3

您正在构建的发电机内的名单,但你(可能)*只是*想要产生值,相反,当你建立它时会产生列表,导致不同。例如,在'DoYield()'中你根本不需要'listResults',你应该只是'产量计数器* 2'直接。 – 2014-10-01 23:17:42

+0

@TomDalton谢谢。和你的意思。但是,我期待'DoYield()'运行的结果是'tic [0]''tic [0,2]'tic [0,2,4]'等等,然后是'toc [0] ''toc [0,2]'等等。我不明白为什么'toc'打印在'tic'语句之间。 – user131983 2014-10-01 23:37:23

+0

@ user131983考虑在我的答案底部运行代码,看看是否有助于解释为什么'toc'打印在'tic'语句之间 – jedwards 2014-10-01 23:52:02

回答

2

这可能是一个更好的例子:

class GeneratorsSample(object): 
    def DoReturn(self): 
     counter, maxCounter = 0, 5 
     listResults = [] 
     while counter < maxCounter: 
      print "tic" 
      listResults.append(counter*2) 
      counter += 1 
     return listResults 

    def DoYield(self): 
     counter, maxCounter = 0, 5 
     while counter < maxCounter: 
      print "tic" 
      yield counter*2 
      counter += 1 
     return 


generatorSample = GeneratorsSample() 

ret = generatorSample.DoReturn() 
yld = generatorSample.DoYield() 

for r in ret: print "toc", r 
for r in yld: print "toc", r 

print ret 
print yld 

首先看看这些行:

for r in ret: print "toc", r 
for r in yld: print "toc", r 

产生相同的数值,但在“回归”的版本,抽动所有放在第一位,那么所有的TOC的。在“良率”版本中,抽搐和toc是散布的。

但是这两种方法之间的主要差异是由这些线所示:

print ret # prints: [0, 2, 4, 6, 8] 
print yld # prints: <generator object DoYield at 0x0000000002202630> 

这里,ret是所产生的所有的值的列表。也就是说,当这项任务是由:产生

ret = generatorSample.DoReturn() 

完整列表然后,并返回的完整列表。

随着发生器的方法,整个列表不是生成的,事实上,没有元素的计算。只需提及一台发电机,根据需要即可生成元件“只有苍蝇”。

换句话说,“返回”的方法:

 
generates a number 
generates a number 
generates a number 
... 
uses that number 
uses that number 
uses that number 
... 

而产生办法:

 
generates a number 
uses that number 
generates a number 
uses that number 
... 

发电机的效率是一个事实,即他们只花时间生成单一元素,因为他们需要(如果他们需要)。如果maxCounter比方说是100万,并且计算比counter * 2更复杂,那么获得第一个输出所花费的时间会有明显的改善。

事实上,你可以看到,通过添加人工延迟(这里,与time.sleep(1)

import time 

class GeneratorsSample(object): 
    def DoReturn(self): 
     counter, maxCounter = 0, 5 
     listResults = [] 
     while counter < maxCounter: 
      v = counter * 2 
      time.sleep(1) 
      print "[DoReturn] computed %d" % v 
      listResults.append(v) 
      counter += 1 
     return listResults 

    def DoYield(self): 
     counter, maxCounter = 0, 5 
     while counter < maxCounter: 
      v = counter * 2 
      time.sleep(1) 
      print "[DoYield] computed %d" % v 
      yield counter*2 
      counter += 1 

     return 


generatorSample = GeneratorsSample() 

ret = generatorSample.DoReturn() 
yld = generatorSample.DoYield() 

for r in ret: print "[return loop] using", r 
print("") 
for r in yld: print "[yield loop] using", r 

输出是:

 
[DoReturn] computed 0 
[DoReturn] computed 2 
[DoReturn] computed 4 
[DoReturn] computed 6 
[DoReturn] computed 8 
[return loop] using 0 
[return loop] using 2 
[return loop] using 4 
[return loop] using 6 
[return loop] using 8 

[DoYield] computed 0 
[yield loop] using 0 
[DoYield] computed 2 
[yield loop] using 2 
[DoYield] computed 4 
[yield loop] using 4 
[DoYield] computed 6 
[yield loop] using 6 
[DoYield] computed 8 
[yield loop] using 8 
+0

非常感谢。很好的解释。 – user131983 2014-10-02 00:34:51

相关问题