Python中list和tuple的区别
概念上的区别list和tuple都是可迭代对象中的容器序列,能够存放不同类型的数据,并且存的是它们所包含的任意类型的对象的引用。这算是两者之间的一个相同点。两者在概念上的不同则是:list中的元素可以改变,也可以对list进行增删操作,如在list末尾增加元素、在list中插入元素、删除某个元素。tuple,也叫元组,可以简单的理解为不可变的列表(list)。一旦定义后,tuple中的元素...
概念上的区别
list和tuple都是可迭代对象中的容器序列,能够存放不同类型的数据,并且存的是它们所包含的任意类型的对象的引用。这算是两者之间的一个相同点。两者在概念上的不同则是:
- list中的元素可以改变,也可以对list进行增删操作,如在list末尾增加元素、在list中插入元素、删除某个元素。
- tuple,也叫元组,可以简单的理解为不可变的列表(list)。一旦定义后,tuple中的元素不能再被改变,也不能增删。
有人可能会举这样的一个例子,对tuple中的元素不可改变提出疑问。
>>> t = (1, 2, [3, 4])
>>> type(t)
<class 'tuple'>
>>> t[2]
[3, 4]
>>> t[2][0] = 10
>>> t
(1, 2, [10, 4])
>>> t[2].extend([20])
>>> t
(1, 2, [10, 4, 20])
>>> t[2] = [5, 6]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
可以看到,tuple中的list改变了,不过这并不是tuple中的元素变了,因为tuple中存的是list的引用,也可以理解为地址。令list中内容改变的两个操作均不改变list的地址,因此也就没有改变tuple中的元素。而最后一步则会在内存中新开辟一个空间,存放[5, 6],再将这个地址赋值给t[2],试图改变tuple中的元素,因此报错了。
元组其实是一种很强大的可以当做记录的数据类型,因此仅仅是把它当做不可变得列表有些埋没其才华。比如:具名元组。
from collections import namedtuple
'''
创建具名元组需要两个参数,一个是类名,一个是类的各个字段的名字。
后者可以是有数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。
因此以下两句等同。
'''
City = namedtuple('City', 'name country population coordinates')
# City = namedtuple('City', ['name', 'country', 'population', 'coordinates'])
# 可以通过以下两种方式声明新的具名元组对象
tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
delhi_data = ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))
delhi = City._make(delhi_data)
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
>>> tokyo.population
36.933
>>> tokyo[1]
'JP'
>>> City._fields
('name', 'country', 'population', 'coordinates')
>>> delhi._asdict()
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', (28.613889, 77.208889))])
>>> for key, value in delhi._asdict().items():
... print(key + ':', value)
...
name: Delhi NCR
country: IN
population: 21.935
coordinates: (28.613889, 77.208889)
>>>
list和tuple一些异同操作
拆包
在将list或tuple中的元素分别赋值给其他变量时,可以直接进行以下操作:
name, country, population, coordinates = ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))
# rest -> ['IN', 21.935]
name, *rest, coordiantes = ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))
还可用*运算符把一个可迭代对象拆开作为函数的参数:
>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
使用拆包可以使代码变得非常优雅
对序列使用*和+
list和tuple均可以进行+与*的操作,构建一个全新的序列,不改变原有的操作对象。结果会被复制给新的变量。
需要提一下*操作。将序列中的值复制n次,若存的元素是引用,复制的也是引用。详见下例:
>>> weird_board = [['_'] * 3] * 3
>>> weird_board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
>>> weird_board[1][2] = '0'
>>> weird_board
[['_', '_', '0'], ['_', '_', '0'], ['_', '_', '0']]
weird_board中存的三个元素是对同一个list的引用,因此改变一个list中的某个值,三个list都会一起被改变。
对于+=和*=操作,是增量赋值。以+=为例,其背后的特殊方法是__iadd__()。list中实现了这个特殊方法,而tuple中没有实现,因此会去调用__add__()方法,效果等于a = a + b。
>>> l = [1, 2, 3]
>>> id(l)
2605965996616
>>> l *= 3
>>> l
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> id(l)
2605965996616
>>> t = (1, 2, 3)
>>> id(t)
2605965945232
>>> t *= 3
>>> t
(1, 2, 3, 1, 2, 3, 1, 2, 3)
>>> id(t)
2605964529240
可以看到在增量乘法操作后,list的地址没有改变,而tuple的地址改变了。
更多推荐
所有评论(0)