【问题标题】:Yield statement in generator causes skipped lines of code生成器中的 yield 语句导致跳过代码行
【发布时间】:2013-11-16 04:48:51
【问题描述】:

我正在用 python 编写一个生成器。它的行为很奇怪,如果我将 yield 语句留在原处,则永远不会调用函数顶部的 print 函数。如果我删除 yield 函数,打印语句会按预期发生。目前这是代码。

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])

删除 yield 可解决此问题。我在这里做错了什么?为了澄清起见,我正在运行 Python 2.7.5。请不要说服我以不同的方式这样做,我的课程需要使用生成器。谢谢!

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

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

    self.assertRaises(ValueError, myGen.next)

【问题讨论】:

  • 在该行执行之前,您必须从生成器中消耗。通过next 或通过for 等迭代它。
  • 您能展示一下您是如何使用该功能的吗?在开始迭代生成器之前,不会执行生成器函数中的代码。

标签: python python-2.7 yield


【解决方案1】:

我怀疑你只是打电话给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】:

    如果您只是调用生成器函数,它将返回生成器对象并且不会执行该函数。您需要在生成器对象上使用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
    

    【讨论】:

      【解决方案3】:

      Python 中的yieldlazy evaluation 的一种样式,简而言之,这意味着序列的连续元素仅在需要时才执行。

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

      和你使用xrange一样,你需要使用你的函数:

      for movement in eachMovement:
          # Do stuff with movement
      

      【讨论】:

      • range 是仅在 Python 3 中的生成器——我认为您的意思是 xrange
      • @Michael0x2a 我其实不知道,谢谢你的提示。也没有发现问题中的版本号:)。固定。
      猜你喜欢
      • 2020-04-07
      • 2011-02-22
      • 2021-07-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 2012-11-27
      • 2022-06-11
      • 2015-07-11
      相关资源
      最近更新 更多