常用数据结构之元组

元组的定义和运算

元组(tuple)

元组和列表的不同之处在于,元组是不可变类型,定义元组通常使用形如(x, y, z)的字面量语法,元组类型支持的运算符跟列表是一样的。

# 定义一个三元组
t1 = (55, 66, 77)
# 查看变量的类型
print(type(t1))  # <class 'tuple'>
# 查看元组中元素的数量
print(len(t1))   # 3
# 索引运算
print(t1[0])     # 55
print(t1[2])     # 66
# 成员运算
print(66 in t1)  # True

()表示空元组,元组中只有一个元素,需要加上一个逗号,否则()就不是代表元组的字面量语法,而是改变运算优先级的圆括号.('hello', )才是一元组,('hello')只是字符串

打包和解包操作

把多个用逗号分隔的值赋给一个变量时,多个值会打包成一个元组类型;当我们把一个元组赋值给多个变量时,元组会解包成多个值然后分别赋给对应的变量,

# 打包操作
a = 1, 10, 100
print(type(a))  # <class 'tuple'>
print(a)        # (1, 10, 100)
# 解包操作
i, j, k = a
print(i, j, k)  # 1 10 100

在解包时,如果解包出来的元素个数和变量个数不对应,会引发ValueError异常,错误信息为:too many values to unpack(解包的值太多)或not enough values to unpack(解包的值不足)。

有一种解决变量个数少于元素的个数方法,就是使用星号表达式。

通过星号表达式,我们可以让一个变量接收多个值,需要注意两点:

1.用星号表达式修饰的变量会变成一个列表,列表中有0个或多个元素;

2.在解包语法中,星号表达式只能出现一次。


a = 1, 10, 100, 1000
i, j, k, *l = a
print(i, j, k, l)     # 1 10 100 [1000]
i, j, k, l, *m = a
print(i, j, k, l, m)  # 1 10 100 1000 []

解包语法对所有的序列都成立,这就意味着我们之前讲的列表、range函数构造的范围序列甚至字符串都可以使用解包语法。

交换变量的值

交换两个变量ab的值

a, b = b, a

如果要将三个变量abc的值互换,即b的值赋给ac的值赋给ba的值赋给c

a, b, c = b, c, a

Python 的字节码指令中有ROT_TWOROT_THREE这样的指令可以直接实现这个操作,效率是非常高的。

元组和列表的比较

  1. 元组是不可变类型,不可变类型更适合多线程环境,因为它降低了并发访问变量的同步化开销。

  2. 元组是不可变类型,通常不可变类型在创建时间上优于对应的可变类型。我们可以使用timeit模块的timeit函数来看看创建保存相同元素的元组和列表各自花费的时间,timeit函数的number参数表示代码执行的次数。下面的代码中,我们分别创建了保存19的整数的列表和元组,每个操作执行10000000次,统计运行时间。

import timeit

print('%.3f 秒' % timeit.timeit('[1, 2, 3, 4, 5, 6, 7, 8, 9]', number=10000000))
print('%.3f 秒' % timeit.timeit('(1, 2, 3, 4, 5, 6, 7, 8, 9)', number=10000000))

 # 输出
 # 0.635 秒
 # 0.078 秒

Python 中的元组和列表类型是可以相互转换的

infos = ('王一帆', 25, True, '广东深圳')
# 将元组转换成列表
print(list(infos))  # ['骆昊', 45, True, '四川成都']

frts = ['apple', 'banana', 'orange']
# 将列表转换成元组
print(tuple(frts))  # ('apple', 'banana', 'orange')