【问题标题】:What is the difference between "range(0,2)" and "list(range(0,2))"?“范围(0,2)”和“列表(范围(0,2))”有什么区别?
【发布时间】:2015-09-22 12:27:21
【问题描述】:

需要了解range(0,2)list(range(0,2))的区别,使用python2.7

两者都返回一个列表,那么究竟有什么区别?

【问题讨论】:

    标签: python python-2.7 python-3.x


    【解决方案1】:

    在 Python 3.x 中,

    range(0,3) 返回一个不可变的可迭代对象类,让您可以对其进行迭代,它不会生成列表,并且它们不会将范围内的所有元素存储在内存中,而是动态生成元素(如您正在迭代它们),而 list(range(0,3)) 生成一个列表(通过迭代所有元素并在内部附加到列表)。

    例子-

    >>> range(0,3)
    range(0, 3)
    >>> list(range(0,3))
    [0, 1, 2]
    

    理想情况下,如果您只想迭代该值范围,range(0,3) 会比 (list(range(0,3)) 快,因为后者在开始迭代之前会产生生成列表的开销。

    在 Python 2.x 中,range(0,3) 生成一个列表,而我们也有一个 xrange() 函数,它具有与 Python 3.x 中的 range() 函数类似的行为(xrange 在 Python 3.x 中被重命名为 range )

    对于 Python 3.5,来自 documentation -

    Range 对象实现 collections.abc.Sequence ABC,并提供包含测试、元素索引查找、切片和支持负索引等功能

    所以你可以做这样的事情 -

    >>> range(0,10)[5]
    5
    >>> range(0,10)[3:7]
    range(3, 7)
    >>> 5 in range(6,10)
    False
    >>> 7 in range(1,8)
    True
    

    所有这些都是常数时间操作,从这个测试中可以看出-

    In [11]: %timeit a = xrange(0,1000000)[1000]
    1000000 loops, best of 3: 342 ns per loop
    
    In [12]: %timeit a = xrange(0,1000000)[10000]
    1000000 loops, best of 3: 342 ns per loop
    
    In [13]: %timeit a = xrange(0,1000000)[100000]
    1000000 loops, best of 3: 342 ns per loop
    
    In [14]: %timeit a = xrange(0,1000000)[999999]
    1000000 loops, best of 3: 342 ns per loop
    
    In [15]: %timeit a = xrange(0,10000000)[9999999]
    1000000 loops, best of 3: 339 ns per loop
    
    In [16]: %timeit a = xrange(0,1000000000000)[9999999999]
    1000000 loops, best of 3: 341 ns per loop
    

    【讨论】:

    • 那么在 Python 3 中 range(x,y) 类似于生成器吗?自从我第一次看到这种行为以来,我一直想知道的事情......
    • 暂时是有意的,因为我用于获取 timeit 示例的在线解释器是 Python 2.7,所以我使用 xrange 而不是 range 。但这应该没关系,因为 Python 3 的范围是 Python 2.x 的 xrange()
    • 好吧,我想是这样的。只是想确保这是故意的。
    【解决方案2】:

    这取决于您使用的 Python 版本。

    在 Python 2.x 中,range() 返回一个列表,因此它们是等价的。

    在 Python 3.x 中,range() 返回一个不可变的序列类型,你需要list(range(0,2)) 来获取一个列表。

    【讨论】:

    • 其实range 没有返回生成器,它是一个不可变对象。尝试做 next(range(0,5)) 。你会明白的。
    • @AnandSKumar 现已更正。
    【解决方案3】:

    基本上,区别在于range(0, 2) 是生成器函数,list(range(0, 2)) 是实际列表。

    在循环中使用生成器函数。例如,文件的生成器函数将逐行读取一个非常大的文件。

    def gen():
        for line in open("hugefile.csv", "r"):
            yield line #Gives back the line every time it is read, but forgets that line after
    
    for line in gen():
        print(line)
    

    这将打印每一行而不会使计算机的 RAM 过载,因为您只是在这两个函数中一一读取。但是,如果我们做类似

    def readEntireFile():
        return [line for line in open("hugefile.csv", "r")] #Python has lazy ways of making lists, this is the same as returning a list with all the lines in the file
    
    for line in readEntireFile():
        print(line)
    

    第二部分看起来一样,但事实并非如此。最初,我们循环遍历文件中的每一行,并在完成后转到下一行。在这里,Python 有一个所有行的列表:/,想象一下用 10GB 的文件来做这件事!你的代码会崩溃。

    现在,让我们回到 range() 和 list(range())

    执行for x in range(0, 6): 会使我们转到范围内的下一个数字,而完全忘记前一个数字(螺丝文法)。

    但是,执行for x in list(range(0, 6)): 将整个数字列表保留在内存中,并且与执行相同

    numlist = [x for x in range(6)]
    for x in numlist:
        print(x)
    

    当您需要代码中的整个数据列表时,请使用 list 方法。但是,当您一次只需要一条数据时(最简单的示例,以块的形式复制文件),请使用生成器函数来节省空间。您可以仅使用 54 mb 复制文件的每 100 万行(假设您没有非常长的行)。但是,如果我们有一个 2kb 的小文件,我们可以在没有生成器的情况下复制那个东西。这不值得花时间,而且在这种情况下速度较慢。

    【讨论】:

      【解决方案4】:

      两个命令都返回Python 2.x 中的列表。但在Python 3.xrange() returns an immutable sequence 中,不是列表。它用于迭代和循环。

      【讨论】:

        【解决方案5】:

        在python3.x中,范围有自己的类型

        >>> range(1)
        range(0, 1)
        >>> type(range(1))
        <class 'range'>
        

        因此,如果您想在 for 循环中使用 range(),那很好。但是您不能将它 purely 用作列表对象。您需要将其转换为列表才能执行此操作。

        Python2 示例:

        >>> L = range(10)
        >>> L[::-1]
        [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
        

        Python3 示例:

        >>> L = range(10)
        >>> L[::-1]
        range(9, -1, -1)
        

        【讨论】:

        • 您可以对范围进行切片 - &gt;&gt;&gt; range(0,3)[1:3] range(1, 3)
        • 正如@AnandSKumar 在他的回答中指出的那样,python3 range() 是一种序列类型,具有与列表和元组相同的操作(除了 concat 和重复)docs.python.org/3/library/…
        • @Anand,您对切片确实有效。我已经更新了我对我的意思的回答。谢谢!
        【解决方案6】:

        Range 生成一个 'range' 类的对象

        是否持续存在取决于是否分配

        a = range(10)
        print(type(a))
        print(a[0])
        print(type(a[0]))
        

        输出:

        <class 'range'>
        0
        <class 'int'>
        

        输出在功能上是一个不可变的有序整数容器。

        从语义上讲,它是一个整数元组,但为了提高效率,Python 将其实现为一个单独的“生成器”类而不是类元组。

        这是一个很好的例子,说明由于缺乏编译,Python 无法隐藏实现细节,程序员必须意识到这些细节。

        【讨论】:

          猜你喜欢
          • 2012-12-11
          • 1970-01-01
          • 2013-12-01
          • 1970-01-01
          • 2014-12-22
          • 2013-08-19
          • 2016-06-25
          • 1970-01-01
          • 2020-06-22
          相关资源
          最近更新 更多