yield在Python 2.7中是什么?

8

可能重复:
Python中的yield关键字解释

好的,我可能表达得不好,但这是我的情况。

我有一行Python 2.7的代码,我正在尝试理解它:

yield (padding_zeros + number_string).encode("ascii")

在这行代码中,padding_zeros是一个由变量数量的'0'组成的字符串,number_string是一个以字符串形式表示的数字,可以是0到10000之间的任何数字。

我非常有信心,.encode("ascii")只是将yield的输出转换为ascii。

我完全不知道yield (padding_zeros + number_string)是做什么的。

我知道它启动了一个生成器,但我已经花了很多时间在网上搜索和阅读语法,但我仍然无法弄清楚生成器实际上什么。这并没有帮助,因为这是我第一次接触Python(我的最终目标是将此代码转换为C#)。

所以,基本上,请有人向我解释一下这行代码的作用?它只是将两个字符串相加,还是做了更复杂的事情?

为了进一步了解背景,这是出现该行代码的块:

for current_length in range(4, max_length + 1):
    for i in range(0, pow(10, current_length)):
        number_string = str(i)
        padding_zeros = "0" * (current_length - len(number_string))
        yield (padding_zeros + number_string).encode("ascii")
(max_length 意思就像它的名字一样 - 表示某个东西的最大长度) 提前感谢您的任何答案(即使告诉我不要太菜):)
编辑:非常感谢您的回答 - 即使我只能选择一个最佳答案,它们都非常有帮助。还要感谢评论 - 其中一些指出,Python 中 "yield" 关键字是什么? 是很好的关于 yield、生成器和迭代的通用指南,即使我没有找到它对我的特定情况的答案 :)

这是Python 2还是Python 3? - Tim Pietzcker
嗨乔治,我认为你的问题在这里已经得到很好的回答了:https://dev59.com/yXVC5IYBdhLWcg3woSpW - MattH
请参考此答案:https://dev59.com/yXVC5IYBdhLWcg3woSpW#231855 - Linus Thiel
2
简短回答你的问题:你解析语句时出错了。yield 产生表达式 (padding_zeros + number_string).encode("ascii"),这是一个 ASCII 字符串,正如你所猜测的那样。可能有帮助的是,像 Python 2 中的 print 一样,yield 不需要在其参数周围加括号。 - alexis
@GeorgePotter:然后您将添加 padding_zeros 和“ASCII编码”的 number_string。由于在此上下文中该编码不起作用,因此它可以工作,但这不是一个好主意。最好删除括号 .encode() - Tim Pietzcker
显示剩余7条评论
4个回答

7

好的,您了解生成器,所以 yield 部分不需要解释。很好。

那么这行代码实际上是做什么的呢?并不是太多:

它连接 padding_zerosnumber_string,然后将结果编码为 ASCII。在 Python 2.7 中,这是一个无操作,因为字符串本身就是 ASCII(根据定义,它只包含 ASCII 数字)。

在 Python 3 中,情况会有所不同;这里的 .encode() 将把字符串转换为 bytes 对象。但在 Python 2 中,这没有任何意义。


谢谢 - 可能这段代码最初是用 Python 3 编写的,这就解释了为什么在 Python 2 中它看起来像一个 no op。虽然不能百分之百确定。感谢您的答案,对于我的无知表示抱歉。 - GeorgePotter

4

yield在生成器中类似于return

当执行到yield时,生成器函数的执行会停止,并返回该值。不同之处在于,当再次调用生成器时,执行将从yield语句处重新开始,直到遇到另一个yield或引发未处理的异常或return语句。return或异常将终止生成器。

生成器的作用是可以像这样调用:x = next(generator)x = generator.next(),每次都会接收到生成器内部yield的值。生成器也是可迭代的,因此它们可以用作循环的源: for x in generator: print x

就像在C#中一样,.运算符会在其左侧出现的对象上调用右侧命名的方法。因此,(padding_zeros + number_string).encode("ascii")会在(padding_zeros + number_string)的结果上调用encode

有关encode的含义,请参见此处:http://docs.python.org/library/stdtypes.html#str.encode

有关语言参考(假设您使用的是Python 2):http://docs.python.org/reference/index.html


1
在这种情况下,yield 用于执行惰性计算。下面的代码大致等效:
def f(...):
    for current_length in range(4, max_length + 1):
        for i in range(0, pow(10, current_length)):
            number_string = str(i)
            padding_zeros = "0" * (current_length - len(number_string))
            yield (padding_zeros + number_string).encode("ascii")

result = list(f())

对比

def f(...):
    result = list()
    for current_length in range(4, max_length + 1):
        for i in range(0, pow(10, current_length)):
            number_string = str(i)
            padding_zeros = "0" * (current_length - len(number_string))
            result.append((padding_zeros + number_string).encode("ascii"))
    return result

result = f()

在代码翻译中,您可以只遵循第二个。


1
除了第二个版本返回一个列表外,生成器将逐个地生成每个元素。 - Marcin
@Marcin 确定。但我不认为 OP 关心那个 :) - Roman Bodnarchuk
了解这两者之间的区别是很好的,但当我开始转换时(仍在为其余部分编写伪代码),这将特别有帮助。 - GeorgePotter

0
一个生成器是一个状态机,它实现了迭代器接口或者在Python中的__iter__。它会在"yield"之后等待,直到你调用next()方法。
试试这个:
def my_gen():
    for current_length in range(4, max_length + 1):
        for i in range(0, pow(10, current_length)):
            number_string = str(i)
            padding_zeros = "0" * (current_length - len(number_string))
            print "generate %s" % i
            yield (padding_zeros + number_string).encode("ascii")

for i in my_gen():
    print "iterate %s" % i

生成器不是状态机-1:http://en.wikipedia.org/wiki/Finite-state_machine。此外,主要的生成器接口是`next`。 - Marcin
我认为这是一个相当简单的问题:每次调用next()都会改变它的状态,从而使其向前移动或停止。(我将第二个“__iter__”编辑为“next()”) - mo.
那不是状态机的定义。 - Marcin
我的理解可能来自于 .NET。在 .NET 中,yield 在编译时生成状态机。我认为 Python 中也是类似的。 - mo.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接