【问题标题】:Unpacking a Python generator into arguments - memory efficient?将 Python 生成器解包到参数中 - 内存效率高吗?
【发布时间】:2014-10-10 07:49:15
【问题描述】:

假设我有一个sets 的生成器:

def f(n) :
  for i in xrange(n) :
    yield set(xrange(i) )

>>> for s in f(5) :
      print s

set([])
set([0])
set([0, 1])
set([0, 1, 2])
set([0, 1, 2, 3])

现在我想union他们。我可以创建一个临时集合列表,并将该列表解压缩为union 的参数:

>>> set.union( * list( f(5) ) )
set([0, 1, 2, 3])

我也可以将生成器本身交给union

>>> set.union( * f(5) )
set([0, 1, 2, 3])

第二种方法是否像第一种方法一样创建完整的临时列表?哪种方法内存效率高?

【问题讨论】:

    标签: python python-2.7 iterator generator


    【解决方案1】:

    Python 在将生成器作为参数应用时first 扩展它;在调用发生之前,生成器生成的所有值都会在两个选项中加载到内存中。

    您可以改用reduce() function 调用:

    from functools import reduce  # Python 3 forward compatibility
    
    reduce(set.union, f(5))
    

    这会逐个迭代f(5) 生成的值,而无需先构建它们的序列。

    演示:

    >>> def f(n):
    ...     for i in xrange(n):
    ...         yield set(xrange(i))
    ... 
    >>> reduce(set.union, f(5))
    set([0, 1, 2, 3])
    

    【讨论】:

      【解决方案2】:

      这两种方法都将评估(并存储)生成器的所有元素。调用函数时,必须在调用函数之前计算整个参数列表。

      你可以通过一个小例子看到这一点:

      def f(n):
          for i in xrange(n) :
              yield set(xrange(i) )
          1/0
      
      def blah(*args):
          print "Blah!"
      
      >>> blah(*f(5))
      Traceback (most recent call last):
        File "<pyshell#56>", line 1, in <module>
          blah(*f(5))
        File "<pyshell#52>", line 4, in f
          1/0
      ZeroDivisionError: division by zero
      

      请注意“废话!”不打印。由于在尝试评估生成器 f(5) 中的所有元素时引发了异常,因此对 blah 的调用永远不会发生。

      【讨论】:

        猜你喜欢
        • 2012-09-22
        • 1970-01-01
        • 2023-03-21
        • 2010-12-02
        • 2015-11-08
        • 2012-02-01
        • 2011-11-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多