【问题标题】:What is a "yield" statement in a function? [duplicate]什么是函数中的“yield”语句? [复制]
【发布时间】:2012-08-17 14:57:06
【问题描述】:

可能重复:
The Python yield keyword explained

谁能在这里向我解释一下 yield 语句在这段代码中的实际作用:

 def fibonacci():
     a, b = 0, 1
     while True:
         yield a
         a, b = b, a+b

for number in fibonacci(): # 使用生成器作为迭代器;打印号码

到目前为止我的理解是,我们正在定义一个函数finonacci(),没有参数? 在函数内部,我们定义 ab 等于 0 和 1,接下来,虽然这是真的,但我们将产生 a。这实际上在做什么?此外,同时产生a? a 现在等于b,而b 现在等于a + b

下一个问题,对于fibonacci() 中的数字,这意味着函数中的每个数字还是什么?我同样对产量和“数量”实际上在做什么感到困惑。显然我知道这意味着fibonacci() 打印号码中的每个号码。我实际上是在不知道数字的情况下定义数字吗?

谢谢,如果我不清楚,对不起。顺便说一句,这是针对 Euler 项目的,如果我知道如何很好地编程,这将是一件轻而易举的事,但我正在努力学习这一点。

【问题讨论】:

    标签: python


    【解决方案1】:

    使用yield 使函数成为生成器。 生成器将在每个循环中继续生成 a 变量,一直等到调用生成器的 next() 方法以继续进行下一次循环迭代。

    或者,直到你 returnStopIteration 被提出。

    稍作修改以显示StopIteration的用法:

    >>> def fib():
    ...     a = 0
    ...     b = 1
    ...     while True:
    ...         yield a
    ...         a = b
    ...         b += a
    ...         if a > 100:
    ...             raise StopIteration
    ...
    >>>
    >>> for value in fib():
    ...     print value
    ...
    0
    1
    2
    4
    8
    16
    32
    64
    >>>
    
    >>> # assign the resulting object to 'generator'
    >>> generator = fib()
    >>> generator.next()
    0
    >>> generator.next()
    1
    >>> for value in generator:
    ...     print value
    ...
    2
    4
    8
    16
    32
    64
    >>>
    

    【讨论】:

    • 在生成器中不需要raise StopIteration - 只需return
    【解决方案2】:

    生成器具有可迭代的特殊属性,它不会为它们的值消耗内存。

    当迭代时需要新值时,他们通过计算新值来做到这一点。

    def f():
        a = 2
        yield a
        a += 1
    
    for ele in f():
        print ele
    

    会打印

     2
    

    因此,您将函数用作不断返回值的可迭代对象。 这在您需要大量内存使用时特别有用,因此您无法负担使用列表推导式

    li = [ele*10 for ele in range(10)]
    

    将整数作为列表占用 10 个内存空间

    但如果你只是想迭代它,不要单独访问它

    改为使用会非常节省内存

    def f():
        i=0
        while i<10
            yield i*10
            i += 1
    

    这将使用 1 个内存空间,因为我不断被重复使用

    一个捷径是

    ge = (i*10 for i in range(10))
    

    您可以执行以下任何操作

    for ele in f():
    
    for ele in li:
    
    for ele in ge:
    

    获得等价的结果

    【讨论】:

      【解决方案3】:

      当代码调用fibonacci 时,会创建一个特殊的生成器对象。请注意,没有代码被执行——只返回一个生成器对象。当您稍后调用其next 方法时,该函数将一直执行,直到遇到yield 语句。返回提供给yield 的对象。当你再次调用next 方法时,函数会再次执行,直到遇到yield。当没有更多的yield 语句并且到达函数末尾时,将引发StopIteration 异常。

      请注意,函数内的对象在对next 的调用之间被保留。这意味着,当代码在下一个循环中继续执行时,在调用 yield 的范围内的所有对象的值都来自上一个 next 调用返回的点。

      生成器最酷的地方在于它们允许使用for 循环进行方便的迭代。 for循环从fibonacci调用的结果中获取一个生成器,然后使用生成器对象的next方法执行循环检索元素,直到遇到StopIteration异常。

      【讨论】:

      • 再次调用fibonacci() 将创建一个新的生成器。
      • 立即返回 a 是什么意思,它保存下一个循环的值 a?
      • @IgnacioVazquez-Abrams 谢谢,我试图写一个非常简单的解释,但写了一些完全无效和尴尬的东西。相应地更正了答案。
      【解决方案4】:

      这个answer 很好地解释了yield 语句以及迭代器和生成器。

      这里具体来说,第一次调用fibonaci()会将a初始化为0,b初始化为1,进入while循环,返回a。 任何下一次调用都将在yield 语句之后开始,影响baa+bb,然后转到while 语句的下一次迭代,再次到达yield 语句,然后再次返回a

      【讨论】:

      • 那么直到 yield 声明之前的一切都只是在设置初始值?然后在语句之后,它只是执行 a, b = b, a+b
      • 第一条语句 a, b = 0, 1 确实是为了初始化。它仅在第一次调用 fibonaci() 时执行。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-23
      • 2020-05-21
      • 2013-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多