【问题标题】:Are there any advantages of non-generator iterators over generators in Python?与 Python 中的生成器相比,非生成器迭代器有什么优势吗?
【发布时间】:2020-02-10 01:10:06
【问题描述】:

在下面的代码中,i1 是一个迭代器。

def sq(x):

    y = []

    for i in x:
        y.append(i**2)

    return y

l1 = range(5)
s1 = sq(l1)
i1 = iter(s1)

我可以为相同的平方运算编写一个生成器。在下面的代码中,g1 是一个生成器。

def sqg(x):

    for i in x:

        yield i**2

g1 = sqg(l1)

我知道生成器使用更少的代码并且更易于读写。我知道生成器也运行得更快,因为它们保持本地状态。

使用i1 比使用g1 有什么优势吗?

【问题讨论】:

  • 请注意,在第一个中您严格地创建了一个完整的列表,而在第二个中您不是。您是在谈论一般的优势,还是特别在这种情况下?这将取决于具体的用例以及您已经拥有哪些数据。
  • 生成器是迭代器。很难说你到底在问什么。
  • @Carcigenicate 我问的是一般的优势。我提供这个例子是为了有一些具体的参考。如果笼统地说太难了,我们来谈谈这个特殊情况。
  • @juanpa.arrivillaga 是的,你是对的:生成器是迭代器的子集。我指的是非生成器迭代器。非生成器迭代器与生成器相比有什么优势吗?我已经相应地修改了我的问题。

标签: python iterator generator


【解决方案1】:

当您调用sq(l1) 时,在sq 内,会填充一个列表y。这会消耗内存,其大小与x 的大小成正比,一旦耗尽。

在第二种情况下,当您调用sqg(l1) 时,sqg 没有任何用于存储结果的内部列表。它直接产生计算值,使其消耗的内存保持不变,并且与 x 的大小无关。

至于非生成器迭代器相对于生成器的优势,我认为没有性能优势,但可能存在结构优势。生成器(一种像您提到的迭代器)被定义为通过调用其中包含 yield 语句的函数返回的迭代器。这意味着您不能向表示生成器的对象添加任何可调用的其他方法,因为这种特殊类型的迭代器是隐式提供给您的。

另一方面,迭代器有一个更宽松的定义:具有__next__ 方法和返回self__iter__ 方法的对象。您可以创建一个遵循上述迭代器标准的类Squares,并且为了获得该迭代器的实例,您必须显式实例化Squares因为您可以控制返回给您的迭代器的属性,所以您可以添加返回该迭代器内部状态的实例方法,这些状态不是通过__next__ 表达的,而使用生成器时您会被锁定到隐式提供给您的生成器对象中。生成器通常会完成这项工作,但有时您需要使用非生成器迭代器来获得所需的控制,而不是 __next__ 提供的功能。

在这种特定情况下,我认为您不需要使用非生成器迭代器为您提供显式控制,因此使用生成器会更好。

【讨论】:

  • 是的,这些我都知道。我的问题是关于迭代器相对于生成器的优势,反之亦然。你的回答——虽然完全正确——回答了相反的问题。
  • @Iterator516 对不起,我完全看错了你的问题,看看我现在是否回答了。
  • 这太棒了!非常感谢!
【解决方案2】:

与生成器相比,创建列表s1 有很多优点 - 它具有定义的长度,您可以对其进行索引和切片,并且可以多次迭代它而无需重新创建它。不过,也许您不会将这些视为非生成器迭代器的优势。

另一个区别是,基于列表的迭代器需要预先完成所有工作,然后缓存结果,而生成器一次只完成一个工作。如果处理任务是资源密集型的,那么列表方法会在生成列表时导致初始暂停,然后运行速度更快(因为您只需从内存中检索结果;还要考虑结果可以缓存在文件中, 例如)。生成器方法不会有初始暂停,但会在生成每个结果时运行得更慢。

【讨论】:

    猜你喜欢
    • 2012-09-27
    • 1970-01-01
    • 2018-11-01
    • 1970-01-01
    • 2017-04-06
    • 2018-05-24
    • 2010-11-04
    • 2020-06-29
    • 2018-05-16
    相关资源
    最近更新 更多