为什么生成器表达式中的"yield from"产生"None"? [英] Why does `yield from` in a generator expression yield `None`s?

查看:133
本文介绍了为什么生成器表达式中的"yield from"产生"None"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

import itertools
for c in ((yield from bin(n)[2:]) for n in range(10)):
    print(c)

输出为:

 0
 None
 1
 None
 1
 0 
 None
 1
 1
 None

...等.为什么出现None?如果我有:

def hmm():
 for n in range(10):
     yield from bin(n)[2:]

for c in hmm():
    print(c)

然后我得到了我期望的结果:

0
1
1
0
1
1

...等.此外,有没有一种方法可以将其写为生成器表达式,以获得与后者相同的结果?

解决方案

yield是一个表达式,其值就是使用send发送到生成器中的值.如果未发送任何内容,则yield的值为无".在您的示例中,yield from会从列表中产生值,但是yield from表达式本身的值是None,这是在封闭的生成器表达式的每次迭代中产生的(即,每个range(10)的值). >

您的示例等效于:

def hmm():
    for n in range(10):
        yield (yield from bin(n)[2:])

for item in hmm():
    print(item)

请注意多余的yield.

如果尝试在生成器表达式中使用yield,则始终会遇到此问题,因为生成器表达式已经产生了其目标值,因此,如果添加显式的yield,则会添加一个额外的表达式( yield表达式),其值也将在生成器中输出.换句话说,像(x for x in range(5))这样的东西已经产生了range(5)中的数字.如果您执行类似((yield x) for x in range(5))的操作,那么除了数字之外,您还将获得yield表达式的值.

据我所知,没有办法使用生成器理解来获得简单的yield from行为(没有额外的None).对于您的情况,我认为您可以通过使用itertools.chain.from_iterable来实现您想要的目标:

for c in itertools.chain.from_iterable(bin(n)[2:] for n in range(10)):
    print(c)

(我意识到您可以通过使用嵌套的for子句:x for n in range(10) for x in bin(n)[2:]在生成器理解中获得yield from行为.但是,我认为这比使用itertools.chain更具可读性. )

I have the following code:

import itertools
for c in ((yield from bin(n)[2:]) for n in range(10)):
    print(c)

The output is:

 0
 None
 1
 None
 1
 0 
 None
 1
 1
 None

... etc. Why do the Nones appear? If I instead have:

def hmm():
 for n in range(10):
     yield from bin(n)[2:]

for c in hmm():
    print(c)

Then I get what I would expect:

0
1
1
0
1
1

... etc. Further, is there a way to write it as the generator expression to get the same result as the latter?

解决方案

yield is an expression, and its value is whatever is sent into the generator with send. If nothing is sent in, the value of yield is None. In your example yield from yields the values from the list, but the value of the yield from expression itself is None, which is yielded at each iteration of the enclosing generator expression (i.e., every value of range(10)).

Your example is equivalent to:

def hmm():
    for n in range(10):
        yield (yield from bin(n)[2:])

for item in hmm():
    print(item)

Note the extra yield.

You will always have this issue if you try to use yield in a generator expression, because the generator expression already yields its target values, so if you add an explicit yield, you are adding an extra expression (the yield expression) whose value will also be output in the generator. In other words, something like (x for x in range(5)) already yields the numbers in range(5); if you do something like ((yield x) for x in range(5)), you're going to get the values of the yield expression in addition to the numbers.

As far as I know, there is no way to get the simple yield from behavior (without extra Nones) using a generator comprehension. For your case, I think you can achieve what you want by using itertools.chain.from_iterable:

for c in itertools.chain.from_iterable(bin(n)[2:] for n in range(10)):
    print(c)

(Edit: I realized you can get the yield from behavior in a generator comprehension by using nested for clauses: x for n in range(10) for x in bin(n)[2:]. However, I don't think this is any more readable than using itertools.chain.)

这篇关于为什么生成器表达式中的"yield from"产生"None"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆