生成器中的Yield语句会导致跳过的代码行

时间:2013-11-16 04:48:51

标签: python python-2.7 yield

我在python中编写一个生成器。它的行为很奇怪,如果我将yield语句保留在原来的位置,那么函数顶部的print函数永远不会被调用。如果我删除yield函数,print语句按预期发生。目前这是代码。

def eachMovement(self):
        print "Each Movement..."

        if not self.isComplete():
            raise ValueError("DressageScore.eachMovement:  dressage score must be designated as complete.")

        for i in range(0, len(self.__iMovementScores)):
            yield (self.__iMovementScores[i], self.__iMovementComments[i])

删除产量可修复此问题。我在这做错了什么?为了澄清,我正在运行Python 2.7.5。请不要说服我以不同的方式做这件事,我的班级要求使用发电机。谢谢!

解: 由于我正在进行测试驱动开发,所以在编写函数的其余部分之前,我编写了raise valueerror测试。在将eachMovement完全转换为生成器之后,我的测试用例失败了,因为它没有设置为测试生成器。愚蠢的错误对我而言。这是现在完成没有问题的测试用例。感谢您的所有帮助

def test1300_910_EachMovementNotComplete(self):
    myGen = self.dsRider.eachMovement()

    self.assertRaises(ValueError, myGen.next)

3 个答案:

答案 0 :(得分:4)

如果只是调用生成器函数,它将返回生成器对象,并且不会执行该函数。您需要在生成器对象上使用next函数或在next生成器对象上调用list函数的其他函数。

def myGen():
    print "Welcome"
    for i in range(10):
        yield i

print myGen()
print list(myGen())
print next(myGen())

<强>输出

<generator object myGen at 0x7f1548366aa0>
Welcome
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Welcome
0

通常,生成器用于迭代(因为一旦生成器耗尽,就不会使用。必须为下一次迭代创建一个新的生成器对象。)所以最好的用法就是这样

for num in myGen():
    print num

<强>输出

Welcome
0
1
2
3
4
5
6
7
8
9

答案 1 :(得分:4)

我怀疑你只是打电话给my_obj.eachMovement(),对吗?

与函数不同,生成器执行称为“惰性求值”的操作。基本上,Python将避免在完全需要之前运行该函数(这很有用,因为它允许您编写返回无限量元素的生成器,允许用户仅使用他们需要的内容,与普通函数相比,会扼杀类似的输入。)

您需要执行以下任一操作:

>>> my_gen = my_obj.eachMovement()
>>> print next(my_gen)
Each Movement...
0  # whatever value

...或类似的东西:

>>> for i in my_obj.eachMovement():
        print i
Each Movement...
0
1
# etc

这两种方法都会强制Python实际评估生成器,因为它需要数据才能继续运行。

答案 2 :(得分:1)

Python中的

yieldlazy evaluation的样式,简而言之,序列的连续元素只在需要时执行。

例如,内置的Python(2.7)函数xrange是一个生成器,Python是一个惰性求值器的术语。

与使用xrange的方式相同,您需要使用以下功能:

for movement in eachMovement:
    # Do stuff with movement