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 _
首先它 yield
是 i
引用的值,例如1
。然后它产生由 yield
操作编辑的值 return,即 None
。它在循环的每次迭代中执行此操作。
for i in x:
_ = yield i
这只是 yield
由 i
引用的值,例如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
,然后您 yield
即 None
。在第二个片段中,你产生了一个对象,然后你保存了那个 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
未捕获已发送数据,部分发送已丢失。
编辑:
忘了解释你的例子中产生的 None
s。
来自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
这段涉及赋值和 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 _
首先它 yield
是 i
引用的值,例如1
。然后它产生由 yield
操作编辑的值 return,即 None
。它在循环的每次迭代中执行此操作。
for i in x:
_ = yield i
这只是 yield
由 i
引用的值,例如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
,然后您 yield
即 None
。在第二个片段中,你产生了一个对象,然后你保存了那个 yield
操作的 "result",但是你 永远不会 yield
结果 ,所以None
没有出现在输出中。
请注意 yield
并不总是 return None
- 这正是您使用 send()
发送给生成器的内容。因为在这种情况下这不算什么,所以你得到 None
。有关 send()
.
赋值语法 ("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
未捕获已发送数据,部分发送已丢失。
编辑:
忘了解释你的例子中产生的 None
s。
来自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