活动地址:CSDN21天学习挑战赛
不可变的列表
。
不可变
是元组的一个重要特性,但是并不是它的全部。元组还能够作为一种记录——没有字段名的记录。
元组的不可变
,是最广为人知的特性。现在主要介绍其记录
的作用。如下一段代码,声明了一个point
元组类型的变量,用于记录一个点的二维坐标。
point = (3, 4)
这里的元组就充当了记录的作用。
你可能会问。什么?就这?我用列表也可以啊。
使用列表的确同样可以达到记录的效果,但是列表是可变序列,而元组是不可变序列。这个不可变很重要。这意味着,你不能随意修改已经创建好的元组中元素的值,也不能随意删除或添加元素,去破坏这项记录的结构。也就是说,用元组记录数据比列表更"安全"
。
所以,从上面的描述中可以看出,对于比较重要的数据记录,我们最好使用元组去存储它们。
很多时候,我们会将序列中的元素取出并保存到其他变量中。如下
point = (3, 4)
x = point[0]
y = point[1]
这样做就实现了获取元组中的元素值。但是这种写法太过冗余。元组拆包能让我们写得更为优雅。
point = (3, 4)
x, y = point
实际上,元组拆包并不仅仅能够用于元组这一数据类型,元组拆包可以应用到任何可迭代对象上
。唯一的硬性要求便是:需要使用相同数量的变量来接收可迭代对象拆包后的所有元素。
当然,如果我们只需要拆包后的一部分元素,也可以使用
*来解决
,这点后面介绍。
tips:由于拆包并不是只能用于元组,所以现在
可迭代元素拆包
这种表达也逐渐流行起来。
最常见的拆包方式,就是平行赋值。
point = 3, 4
x, y = point #元组拆包
还有一种元组拆包最优雅的使用,那便是交换两个变量的值:
x, y = 3, 4
x, y = y, x
我们知道,Python中有一个特殊的标识符,_
空白标识符,可以处理不需要的数据。
point = (3, 4)
#我们不关心y坐标的值
x, _ = point
*
的特殊作用
作为函数参数显式拆包
fun(a, b)
,需要两个参数,而我们此时有一个可迭代对象x = (3, 4)
,刚好其中的两个元素可以作为参数传入函数中。fun(*x)
>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
用来处理拆包后多余的元素
>>> a, b, *rest = range(5)
>>> a, b, rest
(0, 1, [2, 3, 4])
>>> a, b, *rest = range(3)
>>> a, b, rest
(0, 1, [2])
>>> a, b, *rest = range(2)
>>> a, b, rest
(0, 1, [])
对于上面那个前面加上了*
的变量rest
,它会容纳下剩余所有的元素。这个加了*
的变量我们先称其为特殊变量。
特殊变量(带*
前缀的变量)使用规则
在平行赋值中,特殊变量只能出现一个
,即不能出现a, b, *rest1, *rest2 = range(10)
这样的代码,因为特殊变量超过了1个;
特殊变量可以出现在等式左值中的任意位置
。>>> a, *rest, b = range(5) >>> a, rest, b (0, [1, 2, 3], 4)
- 1
- 2
- 3
本来想自己创造一个简单的例子,但是还是为了深入理解,使用书上稍微复杂一点的例子。
metro_areas = [
('Tokyo','JP',36.933,(35.689722,139.691667)),
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
]
print('{:15} | {:^9} | {:^9}'.format('', 'lat.', 'long.'))
fmt = '{:15} | {:9.4f} | {:9.4f}'
for name, cc, pop, (latitude, longitude) in metro_areas:
if longitude <= 0:
print(fmt.format(name, latitude, longitude))
上面代码并不难,我们只抽取涉及到元组拆包的部分,由于使用了循环,我们分析第一次循环的拆包过程。
name, cc, pop, (latitude, longitude) = metro_areas[0]
name
指城市名,cc
指城市所在国家,pop
指人口数,latitude
,longitude
分别指经度和纬度。
从开始的平行赋值处开始:
point = (3, 4)
x, y = point
拆包的主要目的,是将一个数据集合拆开,将集合中的元素抽取出来并将它们单独作为个体来使用。
我们对上面的代码做点小的改动。
point = (3, 4)
(x, y) = point
对的,将等号左值用括号括起来,这样拆包的代码可以看成这样
(x, y) = (3, 4)
通过观察,可以发现,等号左值和右值具有相同的结构,由于具有相同的结构,Python解释器便能够将“包”中的元素对应到变量中。
同样的,嵌套拆包也可以做这样的处理。
仍然使用前面出现过的代码:
name, cc, pop, (latitude, longitude) = ('Tokyo','JP',36.933,(35.689722,139.691667))
很显然, 将等号左值加上括号后,等号两侧结构相同,解释器便能够对其进行拆包赋值。
(name, cc, pop, (latitude, longitude)) = ('Tokyo','JP',36.933,(35.689722,139.691667))