Python中生成器和函数的区别

2024-05-04 23:00:50 发布

您现在位置: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]

Tags: selfreturndefcounterticprintappendwhile
1条回答
网友
1楼 · 发布于 2024-05-04 23:00:50

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

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

生成相同的值,但是在“return”版本中,tic都是首先出现的,然后是所有的toc。在“产量”版本中,tic和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

相关问题 更多 >