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中没有append\extend\remove\pop\index等用法。但是可以使用 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。

你可能感兴趣的:(python)