• python:为什么Tuple操作速度比List快


    Dive into python中说道Tuple是不可变的List,一旦创建了一个Tuple,就不能以任何方式改变它。但是Tuple 比 list 操作速度快。如果您定义了一个值的常量集,并且唯一要用它做的是不断地遍历它,请使用 tuple 代替 list。

    我写了几行代码测试了一下:

    example_list=list()
    for i in range(0,500,1):
        example_list.append(i)
    
    example_tuple=tuple(example_list)
    
    start=time.clock()
    for item in example_list:
        do something
    print " iterate list:",time.clock()-start
    
    
    start=time.clock()
    for item in example_tuple:
       do something
    print " iterate tuple:",time.clock()-start
    

    运行结果如下:

     iterate list: 9.37050717647e-05
     iterate tuple: 6.8270838e-05

    我运行了几次,虽然具体的时间会改变,但是遍历tuple的速度确实比list快。为什么呢?stackoverflow上有人的解释:

    http://stackoverflow.com/questions/3340539/why-is-tuple-faster-than-list 

    大概有以下几个要点:

    1、tuple中是不可变的,在CPython中tuple被存储在一块固定连续的内存中,创建tuple的时候只需要一次性分配内存。但是List被的被存储在两块内存中,一块内存固定大小,记录着Python Object(某个list对象)的信息,另一块是不固定大小的内存,用来存储数据。所以,查找时tuple可以快速定位(C中的数组);list必须遍历(C中的链表)。在编译中,由于Tuple是不可变的,python编译器将它存储在它所在的函数或者模块的“常量表”(constants table)中。运行时,只要找到这些预构建的常量元组。但是List是可变的,必须在运行中构建,分配内存。

    3、当Tuple的元素是List的时候,它只存储list的引用,(C中定长数组里一个元素是指向某个链表的指针),定位查找时它还是会比List快

    4、CPython中已经做了相关优化以减少内存分配次数:释放一个List对象的时候,它的内存会被保存在一个自由List中以重复使用。不过非空list的创建时,仍然需要给它分配内存存储数据。

    Tuple 源码

    class tuple(object):
        """
        tuple() -> empty tuple
        tuple(iterable) -> tuple initialized from iterable's items
        
        If the argument is a tuple, the return value is the same object.
        """
        def count(self, value): # real signature unknown; restored from __doc__
            """ T.count(value) -> integer -- return number of occurrences of value """
            return 0
    
        def index(self, value, start=None, stop=None): # real signature unknown; restored from __doc__
            """
            T.index(value, [start, [stop]]) -> integer -- return first index of value.
            Raises ValueError if the value is not present.
            """
            return 0
    
        def __add__(self, y): # real signature unknown; restored from __doc__
            """ x.__add__(y) <==> x+y """
            pass
    
        def __contains__(self, y): # real signature unknown; restored from __doc__
            """ x.__contains__(y) <==> y in x """
            pass
    
        def __eq__(self, y): # real signature unknown; restored from __doc__
            """ x.__eq__(y) <==> x==y """
            pass
    
        def __getattribute__(self, name): # real signature unknown; restored from __doc__
            """ x.__getattribute__('name') <==> x.name """
            pass
    
        def __getitem__(self, y): # real signature unknown; restored from __doc__
            """ x.__getitem__(y) <==> x[y] """
            pass
    
        def __getnewargs__(self, *args, **kwargs): # real signature unknown
            pass
    
        def __getslice__(self, i, j): # real signature unknown; restored from __doc__
            """
            x.__getslice__(i, j) <==> x[i:j]
                       
                       Use of negative indices is not supported.
            """
            pass
    
        def __ge__(self, y): # real signature unknown; restored from __doc__
            """ x.__ge__(y) <==> x>=y """
            pass
    
        def __gt__(self, y): # real signature unknown; restored from __doc__
            """ x.__gt__(y) <==> x>y """
            pass
    
        def __hash__(self): # real signature unknown; restored from __doc__
            """ x.__hash__() <==> hash(x) """
            pass
    
        def __init__(self, seq=()): # known special case of tuple.__init__
            """
            tuple() -> empty tuple
            tuple(iterable) -> tuple initialized from iterable's items
            
            If the argument is a tuple, the return value is the same object.
            # (copied from class doc)
            """
            pass
    
        def __iter__(self): # real signature unknown; restored from __doc__
            """ x.__iter__() <==> iter(x) """
            pass
    
        def __len__(self): # real signature unknown; restored from __doc__
            """ x.__len__() <==> len(x) """
            pass
    
        def __le__(self, y): # real signature unknown; restored from __doc__
            """ x.__le__(y) <==> x<=y """
            pass
    
        def __lt__(self, y): # real signature unknown; restored from __doc__
            """ x.__lt__(y) <==> x<y """
            pass
    
        def __mul__(self, n): # real signature unknown; restored from __doc__
            """ x.__mul__(n) <==> x*n """
            pass
    
        @staticmethod # known case of __new__
        def __new__(S, *more): # real signature unknown; restored from __doc__
            """ T.__new__(S, ...) -> a new object with type S, a subtype of T """
            pass
    
        def __ne__(self, y): # real signature unknown; restored from __doc__
            """ x.__ne__(y) <==> x!=y """
            pass
    
        def __repr__(self): # real signature unknown; restored from __doc__
            """ x.__repr__() <==> repr(x) """
            pass
    
        def __rmul__(self, n): # real signature unknown; restored from __doc__
            """ x.__rmul__(n) <==> n*x """
            pass
    
        def __sizeof__(self): # real signature unknown; restored from __doc__
            """ T.__sizeof__() -- size of T in memory, in bytes """
            pass
    

     List源码

    class list(object):
        """
        list() -> new empty list
        list(iterable) -> new list initialized from iterable's items
        """
        def append(self, p_object): # real signature unknown; restored from __doc__
            """ L.append(object) -- append object to end """
            pass
    
        def count(self, value): # real signature unknown; restored from __doc__
            """ L.count(value) -> integer -- return number of occurrences of value """
            return 0
    
        def extend(self, iterable): # real signature unknown; restored from __doc__
            """ L.extend(iterable) -- extend list by appending elements from the iterable """
            pass
    
        def index(self, value, start=None, stop=None): # real signature unknown; restored from __doc__
            """
            L.index(value, [start, [stop]]) -> integer -- return first index of value.
            Raises ValueError if the value is not present.
            """
            return 0
    
        def insert(self, index, p_object): # real signature unknown; restored from __doc__
            """ L.insert(index, object) -- insert object before index """
            pass
    
        def pop(self, index=None): # real signature unknown; restored from __doc__
            """
            L.pop([index]) -> item -- remove and return item at index (default last).
            Raises IndexError if list is empty or index is out of range.
            """
            pass
    
        def remove(self, value): # real signature unknown; restored from __doc__
            """
            L.remove(value) -- remove first occurrence of value.
            Raises ValueError if the value is not present.
            """
            pass
    
        def reverse(self): # real signature unknown; restored from __doc__
            """ L.reverse() -- reverse *IN PLACE* """
            pass
    
        def sort(self, cmp=None, key=None, reverse=False): # real signature unknown; restored from __doc__
            """
            L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
            cmp(x, y) -> -1, 0, 1
            """
            pass
    
        def __add__(self, y): # real signature unknown; restored from __doc__
            """ x.__add__(y) <==> x+y """
            pass
    
        def __contains__(self, y): # real signature unknown; restored from __doc__
            """ x.__contains__(y) <==> y in x """
            pass
    
        def __delitem__(self, y): # real signature unknown; restored from __doc__
            """ x.__delitem__(y) <==> del x[y] """
            pass
    
        def __delslice__(self, i, j): # real signature unknown; restored from __doc__
            """
            x.__delslice__(i, j) <==> del x[i:j]
                       
                       Use of negative indices is not supported.
            """
            pass
    
        def __eq__(self, y): # real signature unknown; restored from __doc__
            """ x.__eq__(y) <==> x==y """
            pass
    
        def __getattribute__(self, name): # real signature unknown; restored from __doc__
            """ x.__getattribute__('name') <==> x.name """
            pass
    
        def __getitem__(self, y): # real signature unknown; restored from __doc__
            """ x.__getitem__(y) <==> x[y] """
            pass
    
        def __getslice__(self, i, j): # real signature unknown; restored from __doc__
            """
            x.__getslice__(i, j) <==> x[i:j]
                       
                       Use of negative indices is not supported.
            """
            pass
    
        def __ge__(self, y): # real signature unknown; restored from __doc__
            """ x.__ge__(y) <==> x>=y """
            pass
    
        def __gt__(self, y): # real signature unknown; restored from __doc__
            """ x.__gt__(y) <==> x>y """
            pass
    
        def __iadd__(self, y): # real signature unknown; restored from __doc__
            """ x.__iadd__(y) <==> x+=y """
            pass
    
        def __imul__(self, y): # real signature unknown; restored from __doc__
            """ x.__imul__(y) <==> x*=y """
            pass
    
        def __init__(self, seq=()): # known special case of list.__init__
            """
            list() -> new empty list
            list(iterable) -> new list initialized from iterable's items
            # (copied from class doc)
            """
            pass
    
        def __iter__(self): # real signature unknown; restored from __doc__
            """ x.__iter__() <==> iter(x) """
            pass
    
        def __len__(self): # real signature unknown; restored from __doc__
            """ x.__len__() <==> len(x) """
            pass
    
        def __le__(self, y): # real signature unknown; restored from __doc__
            """ x.__le__(y) <==> x<=y """
            pass
    
        def __lt__(self, y): # real signature unknown; restored from __doc__
            """ x.__lt__(y) <==> x<y """
            pass
    
        def __mul__(self, n): # real signature unknown; restored from __doc__
            """ x.__mul__(n) <==> x*n """
            pass
    
        @staticmethod # known case of __new__
        def __new__(S, *more): # real signature unknown; restored from __doc__
            """ T.__new__(S, ...) -> a new object with type S, a subtype of T """
            pass
    
        def __ne__(self, y): # real signature unknown; restored from __doc__
            """ x.__ne__(y) <==> x!=y """
            pass
    
        def __repr__(self): # real signature unknown; restored from __doc__
            """ x.__repr__() <==> repr(x) """
            pass
    
        def __reversed__(self): # real signature unknown; restored from __doc__
            """ L.__reversed__() -- return a reverse iterator over the list """
            pass
    
        def __rmul__(self, n): # real signature unknown; restored from __doc__
            """ x.__rmul__(n) <==> n*x """
            pass
    
        def __setitem__(self, i, y): # real signature unknown; restored from __doc__
            """ x.__setitem__(i, y) <==> x[i]=y """
            pass
    
        def __setslice__(self, i, j, y): # real signature unknown; restored from __doc__
            """
            x.__setslice__(i, j, y) <==> x[i:j]=y
                       
                       Use  of negative indices is not supported.
            """
            pass
    
        def __sizeof__(self): # real signature unknown; restored from __doc__
            """ L.__sizeof__() -- size of L in memory, in bytes """
            pass
    
        __hash__ = None
    

    List和Tuple相同的用法:

    >>> t = ("a", "b", "mpilgrim", "z", "example") 
    >>> t
    ('a', 'b', 'mpilgrim', 'z', 'example')
    >>> t[0]                                       
    'a'
    >>> t[-1]                                      
    'example'
    >>> t[1:3]                                     
    ('b', 'mpilgrim')
    

     list和tuple定义、索引、分片(slice)方式一样

    List和Tuple不同用法:

    (1)

    >>> t
    ('a', 'b', 'mpilgrim', 'z', 'example')
    >>> t.append("new")    
    Traceback (innermost last):
      File "<interactive input>", line 1, in ?
    AttributeError: 'tuple' object has no attribute 'append'
    >>> t.remove("z")      
    Traceback (innermost last):
      File "<interactive input>", line 1, in ?
    AttributeError: 'tuple' object has no attribute 'remove'
    >>> t.index("example") 
    Traceback (innermost last):
      File "<interactive input>", line 1, in ?
    AttributeError: 'tuple' object has no attribute 'index'
    >>> "z" in t           
    True
    

     从源码也可以看出,tuple中没有appendextend emovepopindex等用法。但是可以使用 in 来查看一个元素是否存在于 tuple 中

    (2)

    d=dict()
    d[example_tuple]="a"
    d[example_list]="b"

    Traceback (most recent call last):
      File "N:/WorkSpace/python-workspace/tuple_test.py", line 15, in <module>
        d[example_list]="b"
    TypeError: unhashable type: 'list'

    tuple2=([2,3,4,5],[1,2,4,5])
    d=dict()
    d[tuple2]="a"

    Traceback (most recent call last):
      File "N:/WorkSpace/python-workspace/tuple_test.py", line 14, in <module>
        d[tuple2]="a"
    TypeError: unhashable type: 'list'

    Tuples 可以在 dictionary 中被用做 key,但是 list 不行。实际上,事情要比这更复杂。Dictionary key 必须是不可变的。Tuple 本身是不可改变的,但是如果您有一个 list 的 tuple,那就认为是可变的了,用做 dictionary key 就是不安全的。只有字符串、整数或其它对 dictionary 安全的 tuple 才可以用作 dictionary key。

    Tuple和List相互转换:

    example_list=list()
    for i in range(0,10,1):
        example_list.append(i)
    
    example_tuple=tuple(example_list)
    example_list2=list(example_tuple)
    print "tuple",example_tuple
    print "list",example_list2
    

    运行结果:

    tuple (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    内置的 tuple 函数接收一个 list,并返回一个有着相同元素的 tuple。而 list 函数接收一个 tuple 返回一个 list。

  • 相关阅读:
    winform 通过左右键,或enter键做类似Tab键的功能
    向表中插入查询结果
    创建Oracle job的一些注意事项
    多数据库独立主机的配置
    图形码验证
    JavaScript中的trycatchfinally
    ASP.Net生成后台脚本的问题的解决办法
    10个你未必知道的CSS技巧
    学习JQuery的$.Ready()与OnLoad事件比较[转]
    风雨20年:我所积累的20条编程经验[csdn]
  • 原文地址:https://www.cnblogs.com/sueZheng/p/4660075.html
Copyright © 2020-2023  润新知