【问题标题】:How to identify a generator vs list comprehension如何识别生成器与列表理解
【发布时间】:2013-08-15 06:00:24
【问题描述】:

我有这个:

>>> sum( i*i for i in xrange(5))

我的问题是,在这种情况下,我是通过列表理解还是生成器对象来 sum ?我该怎么说?对此有一般规则吗?

还要记住 sum 本身需要一对括号来包围它的参数。我认为上面的括号是求和,而不是创建生成器对象。你不同意吗?

【问题讨论】:

    标签: python generator list-comprehension generator-expression


    【解决方案1】:

    您正在传递generator expression

    list comprehension is specified with square brackets ([...])。列表推导首先构建一个 列表对象,因此它使用与列表文字语法密切相关的语法:

    list_literal = [1, 2, 3]
    list_comprehension = [i for i in range(4) if i > 0]
    

    另一方面,生成器表达式创建一个迭代器对象。只有在 over 迭代该对象时,才会执行包含的循环并生成项目。生成器表达式不保留这些项目;没有正在构建的列表对象。

    生成器表达式总是使用(...) 圆括号,但是当用作调用的only 参数时,括号可以省略;以下两个表达式是等价的:

    sum((i*i for i in xrange(5)))  # with parenthesis
    sum(i*i for i in xrange(5))    # without parenthesis around the generator
    

    引用生成器表达式文档:

    只有一个参数的调用可以省略括号。详见Calls部分。

    【讨论】:

    • @Martin Pieters 但是请记住 sum 本身需要一对括号来包围它的参数。我认为上面的括号是用于求和而不是用于创建生成器对象。你不同意吗?
    • @abc:我只是在解决这个问题;在这种情况下,生成器周围的括号是可选的
    • @Martin Pieters 太好了,我现在看到你的更新了。那是我遇到的真正紧迫的问题。谢谢。
    【解决方案2】:

    列表推导包含在[]

    >>> [i*i for i in xrange(5)]  # list comprehension
    [0, 1, 4, 9, 16]
    >>> (i*i for i in xrange(5))  # generator
    <generator object <genexpr> at 0x2cee40>
    

    你正在传递一个生成器。

    【讨论】:

      【解决方案3】:

      那是一个生成器:

      >>> (i*i for i in xrange(5))
      <generator object <genexpr> at 0x01A27A08>
      >>>
      

      列表推导包含在[] 中。

      【讨论】:

        【解决方案4】:

        您可能还会问,“这种语法真的会导致 sum 一次使用一个生成器,还是它会先秘密地为生成器中的每个项目创建一个 list”?检查这一点的一种方法是在非常大的范围内尝试它并观察内存使用情况:

        sum(i for i in xrange(int(1e8)))
        

        这种情况下的内存使用是恒定的,range(int(1e8)) 创建完整列表并消耗数百 MB 的 RAM。

        您可以测试括号是可选的:

        def print_it(obj):
            print obj
        
        print_it(i for i in xrange(5))
        # prints <generator object <genexpr> at 0x03853C60>
        

        【讨论】:

        • 有关检查 ram 使用情况以检测列表理解或生成器表达式的非常有用的信息。谢谢。
        【解决方案5】:

        我试过了:

        #!/usr/bin/env python
        
            class myclass:
        
                    def __init__(self,arg):
                            self.p = arg
                            print type(self.p)
                            print self.p
        
        
        
        
        
            if __name__ == '__main__':
        
                    c = myclass(i*i for i in xrange(5))
        

        然后打印出来:

        $ ./genexprorlistcomp.py 
        <type 'generator'>
        <generator object <genexpr> at 0x7f5344c7cf00>
        

        这与 Martin 和 mdscuggs 在他们的帖子中解释的一致。

        【讨论】:

          【解决方案6】:

          您正在传递一个生成器对象,列表理解被 [] 包围。

          【讨论】:

          • 但是记住 sum 本身需要一对括号来包围它的参数。我认为上面的括号是用于sum 而不是用于创建生成器对象。你不同意吗?
          猜你喜欢
          • 2013-12-30
          • 2016-10-04
          • 2023-02-02
          • 1970-01-01
          • 2017-08-05
          • 2014-02-28
          • 2015-07-18
          • 2021-04-07
          相关资源
          最近更新 更多