Python:yield和yield赋值

Python: yield and yield assignment

这段涉及赋值和 yield 运算符的代码如何工作?结果相当混乱。

def test1(x): 
    for i in x:
        _ = yield i 
        yield _
def test2(x): 
    for i in x:
        _ = yield i 

r1 = test1([1,2,3])
r2 = test2([1,2,3])
print list(r1)
print list(r2)

输出:

[1, None, 2, None, 3, None] 
[1, 2, 3]
_ = yield i 
yield _

首先它 yieldi 引用的值,例如1。然后它产生由 yield 操作编辑的值 return,即 None。它在循环的每次迭代中执行此操作。

for i in x:
    _ = yield i

这只是 yieldi 引用的值,例如1,然后继续循环的下一次迭代,产生 2,然后是 3

return不同,yield关键字可以用在表达式中:

x = return 0 # SyntaxError
x = yield 0 # perfectly fine

现在,当解释器看到 yield 时,它会生成指定的值。但是,当它这样做时,该操作 return 的值 None,就像 mylist.append(0)print('hello')return 的值 None 一样。当您将该结果分配给 _ 之类的引用时,您正在保存 None.

因此,在第一个片段中,您产生了一个对象,然后您保存了 yield 操作的 "result",即 None,然后您 yieldNone。在第二个片段中,你产生了一个对象,然后你保存了那个 yield 操作的 "result",但是你 永远不会 yield 结果 ,所以None 没有出现在输出中。

请注意 yield 并不总是 return None - 这正是您使用 send() 发送给生成器的内容。因为在这种情况下这不算什么,所以你得到 None。有关 send().

的更多信息,请参阅 this answer

赋值语法 ("yield expression") 允许您将生成器视为基本协程。

首次提出于PEP 342 and documented here: https://docs.python.org/2/reference/expressions.html#yield-expressions

与生成器一起工作的客户端代码可以使用其 send() 方法将数据传回生成器。可以通过赋值语法访问该数据。

send() 也会迭代 - 所以它实际上包含一个 next() 调用。

使用您的示例,这就是使用协程功能的情况:

>>> def test1(x):
...     for i in x:
...         _ = yield i
...         yield _
...
>>> l = [1,2,3]
>>> gen_instance = test1(l)

>>> #First send has to be a None
>>> print gen_instance.send(None)
1
>>> print gen_instance.send("A")
A
>>> print gen_instance.send("B")
2
>>> print gen_instance.send("C")
C
>>> print gen_instance.send("D")
3
>>> print gen_instance.send("E")
E
>>> print gen_instance.send("F")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

请注意,由于每个循环迭代中的第二个 yield 未捕获已发送数据,部分发送已丢失。

编辑: 忘了解释你的例子中产生的 Nones。

来自https://docs.python.org/2/reference/expressions.html#generator.next

When a generator function is resumed with a next() method, the current yield expression always evaluates to None.

next()在使用迭代语法时使用。

为了扩展 TigerhawkT3 的答案,yield 操作在您的代码中返回 None 的原因是因为 list(r1) 没有发送任何东西 发电机。试试这个:

def test1(x):
    for i in x:
        _ = yield i
        yield _


r1 = test1([1, 2, 3])

for x in r1:
    print('   x', x)
    print('send', r1.send('hello!'))

输出:

   x 1
send hello!
   x 2
send hello!
   x 3
send hello!

这是一个有点虚构的示例,其中将值发送到生成器可能很有用:

def changeable_count(start=0):
    current = start
    while True:
        changed_current = yield current
        if changed_current:
            current = changed_current
        else:
            current += 1

counter = changeable_count(10)

for x in range(20):
    print(next(counter), end=' ')

print()
print()

print('Sending 51, printing return value:', counter.send(51))
print()

for x in range(20):
    print(next(counter), end=' ')

print()
print()

print('Sending 42, NOT printing return value')
print()

counter.send(42)

for x in range(20):
    print(next(counter), end=' ')

print()

输出:

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 

Sending 51, printing return value: 51

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 

Sending 42, NOT printing return value

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62