【问题标题】:yield break in PythonPython中的产量中断
【发布时间】:2011-09-17 17:07:09
【问题描述】:

根据对这个question的回答,C#中的yield break相当于Python中的return。在正常情况下,return 确实会停止生成器。但是如果你的函数只做return,你会得到一个None而不是一个空的迭代器,它在C#中由yield break返回

def generate_nothing():
    return

for i in generate_nothing():
    print i

你会得到一个TypeError: 'NoneType' object is not iterable, 但是如果我在return 之前添加并且从不运行yield,这个函数会返回我所期望的。

def generate_nothing():
    if False: yield None
    return

它有效,但看起来很奇怪。你有更好的主意吗?

【问题讨论】:

  • 这就是 Python 的工作原理。我不认为你真的需要最后的return。 Python 不是 C#。不要指望它们的工作方式相同。
  • 没有yield 的函数不是生成器。因此,您的第一个示例仅返回 None 并尝试对其进行迭代。
  • @Jochen:那不是生成器。它是一个可迭代的生成对象。虽然正如我在 phihag 的回答中所说,这不太重要。

标签: python generator yield


【解决方案1】:
def generate_nothing():
    return
    yield

【讨论】:

  • 这将在 linter 中创建一个 code is unreachable 警告。
  • @congusbongus 通常你想在某些条件下从生成器中中断,所以使用if <condition>: return而不是裸return
【解决方案2】:

处理这个问题的一个好方法是引发StopIteration,这是当你的迭代器没有任何东西可以产生并且next()被调用时引发的。这也将优雅地跳出 for 循环,循环内没有任何内容执行。

例如,给定一个元组(0, 1, 2, 3),我想得到重叠对((0, 1), (1, 2), (2, 3))。我可以这样做:

def pairs(numbers):
    if len(numbers) < 2:
        raise StopIteration

    for i, number in enumerate(numbers[1:]):
        yield numbers[i], number

现在pairs 可以安全地处理数量为 1 或更少的列表。

【讨论】:

  • 请注意,从 vs 3.6 开始,这是一个坏主意,因为在实现 PEP 479 后,StopIteration 将被转换为 RuntimeError,以防止在使用子生成器时出现问题。跨度>
  • 在任何版本中都是个坏主意;只是return
  • 虽然这是功能性的(目前),return 更好;所描述的功能甚至包含在return documentation中。
【解决方案3】:
def generate_nothing():
    return iter([])

【讨论】:

  • xrange(0)range(0) 在 3.x 中)。
  • 这两者的速度大约是return; yield 的两倍。但请注意,这些将返回 &lt;type 'listiterator'&gt;&lt;type 'xrange'&gt; 类型的对象,它们都是 object 的直接子类型 - 所以它们不是生成器。这可能并不重要。仅出于学术兴趣:-)
  • @Chris:在 python3 中,我的时钟速度只快了大约 20-30%,尽管从质量上看,它似乎稍微减少了内存压力(不是严格的测试:z=[list(f()) for _ in range(10**7)])跨度>
【解决方案4】:

有趣的是这两个函数具有相同的字节码。当字节码编译器找到yield 关键字时,可能有一个标志设置为generator

>>> def f():
...   return

>>> def g():
...   if False: yield 
#in Python2 you can use 0 instead of False to achieve the same result


>>> from dis import dis
>>> dis(f)
2           0 LOAD_CONST               0 (None) 
            3 RETURN_VALUE
>>> dis(g)
2           0 LOAD_CONST               0 (None) 
            3 RETURN_VALUE

【讨论】:

  • 嗯?他们相差甚远。再次检查您的结果。你在某个地方犯了一个错误。
  • @Chris 是的,Python2 不会优化它,因为 False 不是关键字,也可能不是错误值。 Python3 可以。
  • 甜蜜。它甚至不为 yield 语句生成字节码
  • @JBernado:嗯,我看到这在 Python 3 中是可能的。起初我在想,如果 False 被分配一个不同的值,那将是一个明显的问题。我忘记了TrueFalse 是Python 3 中的关键字。并且使用相同的字节码,我认为区别在于f.__code__.co_flags == 67g.__code__.co_flags == 99。这表明第六位标志将其标记为生成器。很抱歉批评你 - 但你现在真的应该将它标记为 Python 3 以生成相同的字节码。
  • @Chris 我已经在我的回答中发表了评论 :) 在 Python 2 中,您可以使用 0 而不是 False
猜你喜欢
  • 2012-11-11
  • 2013-09-14
  • 2010-12-01
  • 2021-02-23
  • 2014-06-16
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 2015-08-17
相关资源
最近更新 更多