流畅的Python读书笔记(二)序列:元组

活动地址:CSDN21天学习挑战赛

流畅的Python读书笔记(二)序列:元组


初学Python时,常常会听到被人将元组称作 不可变的列表不可变是元组的一个重要特性,但是并不是它的全部。元组还能够作为一种记录——没有字段名的记录。

元组不仅仅是不可变的列表

元组的不可变,是最广为人知的特性。现在主要介绍其记录的作用。如下一段代码,声明了一个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,它会容纳下剩余所有的元素。这个加了*的变量我们先称其为特殊变量。

      • 特殊变量(带*前缀的变量)使用规则

        1. 在平行赋值中,特殊变量只能出现一个,即不能出现a, b, *rest1, *rest2 = range(10)这样的代码,因为特殊变量超过了1个;

        2. 特殊变量可以出现在等式左值中的任意位置

        >>> a, *rest, b = range(5)
        >>> a, rest, b
        (0, [1, 2, 3], 4)
        

嵌套元组拆包

本来想自己创造一个简单的例子,但是还是为了深入理解,使用书上稍微复杂一点的例子。

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指人口数,latitudelongitude分别指经度和纬度。

关于拆包的一点个人理解

从开始的平行赋值处开始:

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))

参考资料

  • 流畅的Python
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值