【问题标题】:Using return (list) vs yield使用 return (list) vs yield
【发布时间】:2020-02-18 01:13:18
【问题描述】:

我创建了两个枚举方法,一个返回一个列表,另一个返回一个产量/生成器:

def enum_list(sequence, start=0):
    lst = []
    num = start
    for sequence_item in sequence:
        lst.append((num, sequence_item))
        num += 1
    return lst


def enum_generator(sequence, start=0):
    num = start
    for sequence_item in sequence:
        yield (num, sequence_item)
        num += 1

关于这个的几个问题:

(1) 将列表更改为生成器就这么简单:

# build via list
l = list()
for item in items:
    l.append(item)

# build via iterator
# l = list() (1) <== delete this line
for item in items:
    yield item # (2) change l.append(...) to yield ...

(2) “惰性求值”是使用生成器的唯一原因,还是还有其他原因?

【问题讨论】:

  • 很难理解你在这里问什么。“将数组(你的意思是列表吗?)更改为生成器”是什么意思?
  • @juanpa.arrivillaga 更新了问题。
  • 再说一次,我不太确定你在问什么。生成器是一种语言结构,可让您轻松编写迭代器,其方式通常比使用完整的迭代器协议更容易理解/更具表现力。列表和生成器是两个不同的东西。列表是容器,生成器是迭代器。

标签: python python-3.x generator


【解决方案1】:

(1) 生成器只需将 yield 添加到您的迭代中即可创建。

(2) 是的,用于惰性求值。但是生成器也用于创建堆栈和队列,因为它们只能迭代一次。通过yielding上下文,上下文管理器也可以利用此属性。

【讨论】:

  • @juanpa.arrivillaga 真的谢谢你,我又犯了同样的错误,混淆了迭代器和生成器。
  • @juanpa.arrivillaga 不太清楚你为什么这么说。生成器类也是生成器,并且定义了__iter____next__,它不需要yield 成为生成器。例如,stackoverflow.com/questions/42983569/…
  • @blhsing 没有“生成器类”之类的东西。一个类可以实现iterator protocol,在这种情况下,它可以是一个iterator。所有的生成器都是迭代器,并不是所有的迭代器都是生成器。如果它不使用yield,那么它就不是一个生成器(除非它是一个生成器表达式)。所以自己尝试一下,使用链接答案中的示例迭代器和import types; print(isinstance(Fib(), types.GeneratorType))
  • @juanpa.arrivillaga 刚刚查找了生成器的官方词汇表。您确实是对的,生成器的精确定义是产生的函数。我猜人们只是简单地将可迭代类与生成器混为一谈,以至于它们实际上可以互换使用,这一点从 SO 上“生成器类”一词的许多用法就可以看出,直到现在没有任何更正。所以感谢您指出并清理它。 :-)
  • @blhsing,此外,了解 iterable objectiterator object 之间的区别也很重要。另一件经常被误解/掩盖的事情。我发誓我不仅仅是一个书呆子,这实际上很重要。至少,它会让你在面试中看起来很好:)
【解决方案2】:

您的情况的另一个区别是,由于列表是在使用之前创建的,并且在每次下次调用时都会评估生成器,因此生成器函数可以检查上下文并为每个产量得出不同的结果,具体取决于外部条件,随时间变化。

考虑伪代码:

def alloted_time():
    while True:
         if len(global_queue)>10:
            yield 5
         else:
            yield 10

如果队列很大,则为下一个人分配 5 分钟,否则为 10 分钟。

【讨论】:

  • 要使它成为一个有用的 生成器,你可能需要一个while True: 来围绕整个事情。否则,无论你使用哪个代码路径,都只有一个yield,这基本上只是一个使用不便的功能。
  • @ShadowRanger 当然!我觉得我错过了什么,谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-01-04
  • 2016-06-21
  • 2023-03-21
  • 1970-01-01
  • 2011-02-08
  • 1970-01-01
  • 2017-01-09
  • 1970-01-01
相关资源
最近更新 更多