元组 这个被经常忽略的神器
元组是不可变的列表,这句话并没有完全概括元组的特点,还有很多有用的特性,在平时编码的时候不应该忽略,还可以用于没有字段名的记录。元组作为记录使用。下面就来看下这个神奇的威力!
元组和记录
元组中的内个元素都存放了记录中一个字段的数据,要加这个字段的位置。这个位置是比较重要的。
如果把元组当做是一些字段的集合,那么数量和位置信息变得非常重要。
元组拆包
元组拆包就把元组当做记录来使用
city, year, pop, chg, area = ("Tokyo", 2003, 32450, 0.66, 8014)
这样一一对应,就是拆包,这样的形式是平行赋值。
元组拆包可以应用到任何可迭代对象上面,唯一的硬性要求就是,被可迭代对象中的元素数量必须要跟接受这些元素的元组空挡数一致。除非用 * 表示忽略多余的元素。
*运算符把一个可迭代对象拆解为函数的参数
print(divmod(20, 8)) # (2, 4)
t = (20, 8)
print(divmod(*t)) # (2, 4)
quotient, remainder = divmod(*t)
print(quotient, remainder) # 2 4
# 说明: divmod(a,b)函数的作用是 取a,b 之间的取整和取余
# c1 = a // b quotient = 20 // 8
# c2 = a % b remainder = 20 % 8
交换两个值的位置比较优雅的做法
a, b = b, a
使用 _ 作为占位符使用,当我们不是随所有的元组元素感兴趣的话可以使用 _
os.path.split() 函数会返回以路径和最后一个文件名字组成的元组(path, last_part)
import os
_, filename = os.path.split("/home/python/aa.py")
print(filename) # aa.py
元组拆包 *
使用* 来处理剩下的元素
使用*args 来获取不确定数量的参数
a, b, *rest = range(5)
print(a, b, rest)# 0 1 [2, 3, 4]
a, b, *rest = range(3)
print(a, b, rest) # 0 1 [2]
a, b, *rest = range(2)
print(a, b, rest)# 0 1 []
# * 前缀只能用在一个变量前面,但是这个变量可以出现在赋值表达式的任意位置
a, b, *rest, c, d = range(6)
print(a, b, rest, c, d)#0 1 [2, 3] 4 5
嵌套元组拆包
metro_area = [
('Tokyo', 'jp', 36.333, (35.28357, 139.67362)),
('Delhi Ncy', 'IN', 21.539, (28.28357, 77.67362)),
]
print('{:5} | {:^9} |{:^9}'.format('', 'lat', 'long.'))
fmt = '{:15} | {:9.4f} |{:9.4f}'
for name, cc, pop, (latitude, longitude) in metro_area:
if longitude >=0 :
print(fmt.format(name, latitude, longitude))
# | lat | long.
#Tokyo | 35.2836 | 139.6736
#Delhi Ncy | 28.2836 | 77.6736
上面输出元组可以看到,嵌套的元组直接拆包
具名元组
注意观察会发现,我们时常需要给记录中的字段命名
使用collections.namedtuple() 函数来实现,构建一个带字段名的元组和一个有名字的类。
用namedtuple 构建的类的实例所消耗的内存和元组是一样的,因为字段名都被保存在对应的类中。这个实例和普通的对象实例比起来也要小一些,因为python 不会用dict 来存放一些实例属性。
使用具名元组来记录一个城市的信息
from collections import namedtuple
City = namedtuple("City", 'name country population coordinates')
tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
print(tokyo) # City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
print(tokyo.name) # Tokyo
print(tokyo[1])# JP
print(tokyo.country) #JP
print(tokyo.population)# 36.933
print(tokyo.coordinates)#(35.689722, 139.691667)
具名元组的属性和方法
from collections import namedtuple
City = namedtuple("City", 'name country population coordinates')
tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
print(City._fields)
Latlong = namedtuple('Latlong', 'lat long')
delhi_data = ('Delhi NCR', 'IN', 21.935, Latlong(28.6139, 77.1233))
# 使用_make() 通过接受一个可迭代的对象来生成一个类的实例。作用和 City(*delhi_data) 是一样的
delhi = City._make(delhi_data)
print(delhi._asdict())
# _asdict() 把具名元组以collections.OrderedDict 的形式返回,利用这个吧信息呈现出来
for key, value in delhi._asdict().items():
print(key + ':', value)
下面是控制台的输出
#('name', 'country', 'population', 'coordinates')
#OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', #Latlong(lat=28.6139, long=77.1233))])
#name: Delhi NCR
#country: IN
#population: 21.935
#coordinates: Latlong(lat=28.6139, long=77.1233)
元组作为不可变列表
和变化的相比,根增减元素相关的方法之外,元组支持列表的其他所有方法。元组没有reversed() 方法 但是 reversed(my_tuple) 是可以使用的。
不可变就不可以进行增减和删除修改操作。
不可变,如果直接赋值的话就是新创建对象,但是可变化列表,当增加元素,对象的引用不变。