元组也是多个元素按照一定的顺序构成的序列。元组和列表的不同之处在于,元组是不可变类型,这就意味着元组类型的变量一旦定义,其中的元素不能再添加或删除,而且元素的值也不能进行修改。
元组很多地方都和列表很像,只需要记住元组生成后不可改变,你就基本掌握了元组。
定义元组通常使用()
字面量语法,元组类型支持的运算符跟列表是一样。下例演示了元组的定义
# 定义一个三元组
t1 = (45, 9, 32)
# 定义一个四元组
t2 = ( 26, True, '成都',23.33)
# 还可以使用tuple()把列表等数据类型转换成元组
a = '1,234,567,89'
t1 = tuple(map(int, a.split(',')))
print(t1) # (1, 234, 567, 89)
t2 = tuple(range(4)) # (0, 1, 2, 3)
print(t2)
t3 = tuple(zip(t1, t2)) # ((1, 0), (234, 1), (567, 2), (89, 3))
print(t3)
list1 = [x for x in range(6)]
t4 = tuple(list1) # (0, 1, 2, 3, 4, 5)
print(t4)
一个元组中有几个元素,我们就称之为几元组。
注意:()
表示空元组,但是如果元组中只有一个元素,需要加上一个逗号,否则()
就不是代表元组的字面量语法,而是改变运算优先级的圆括号,即(100, )
才是一元组,而(100)
只是整数。下例是代码验证。
# 空元组
t1 = ()
print(type(t1)) #
# 不是元组
t2 = (100)
print(type(t2)) #
# 一元组
t3 = (100, )
print(type(t3)) #
元组的运算
# 查看变量的类型
print(type(t1), type(t2)) #
# 查看元组中元素的数量
print(len(t1), len(t2)) # 3 4
# 通过索引运算获取元组中的元素
print(t1[0], t1[-3]) # 45 45
print(t2[3], t2[-1]) # 23.33 23.33
# 循环遍历元组中的元素
for member in t2:
print(member)
# 成员运算
print(90 in t1) # False
print(26 in t2) # True
# 拼接
t3 = t1 + t2
print(t3) # (45, 9, 32, 26, True, '成都')
# 切片
print(t3[::3]) # (45, 26, 23.33)
# 比较运算
print(t1 == t3) # False
print(t1 >= t3) # False
print(t1 < (45, 11, 32)) # True
当我们把多个用逗号分隔的值赋给一个变量时,多个值会打包成一个元组类型;当我们把一个元组赋值给多个变量时,元组会解包成多个值然后分别赋给对应的变量,如下例所示。
# 打包
a = 1, 10, 100
print(type(a), a) # (1, 10, 100)
# 解包
i, j, k = a
print(i, j, k) # 1 10 100
在解包时,如果解包出来的元素个数和变量个数不对应,会报错。
解包时如果变量个数小于元素个数,可以使用星号表达式接受多余的所有元素,接受的元素会变成列表,星号表达式也可以接收空值,变成空列表,星号表达式只能有一个,如下例示
a = 1, 10, 100, 1000
i, j, *k = a
print(i, j, k) # 1 10 [100, 1000]
i, *j, k = a
print(i, j, k) # 1 [10, 100] 1000
i, j, k, l, *m = a
print(i, j, k, l, m) #1 10 100 1000 []
解包语法对所有的序列都成立,这就意味着对字符串、列表以及我们之前讲到的range
、zip、map这些函数返回的范围序列都可以使用解包语法。如下例示
a, b, *c = range(1, 10)
print(a, b, c) # 1 2 [3, 4, 5, 6, 7, 8, 9]
a, b, c = [1, 10, 100]
print(a, b, c) # 1 10 100
a, *b, c = 'hello'
print(a, b, c) # h ['e', 'l', 'l'] o
a, b, *c = map(str, 'happy')
print(a, b, c) # h a ['p', 'p', 'y']
a, b, *c = zip('hello', 'happy')
print(a, b, c) # ('h', 'h') ('e', 'a') [('l', 'p'), ('l', 'p'), ('o', 'y')]
很容易发现如果把打包解包操作一起写的话,不就是python中交换变量值的一种方法吗,如下例示
a, b = b, a
a, b, c = b, c, a
a, b, c, d = d, c, b, a
这样就可以交换对应变量的值,不过要知道的是虽然这样可以实现打包解包操作,但是两个或三个变量的值的交换其实并不会用到打包解包操作,python中有专门的这样交换变量的命令实现这个功能,效率更高,只有需要交换的变量数大于三个时才会用打包解包来实现这个功能。
元组是一种不可变类型这是它最大的特点,不可变类型更加安全,不用担心多人访问可能导致的数据被更改的问题,也降低了访问的开销,而且通常不可变类型创建时间和占用空间都更小,空间占用可以用sys模块中getsizeof函数查看其占用空间来证明,时间方面可以用timeit模块中的timeit证明。如下例示。
import sys
import timeit
a = list(range(100000))
b = tuple(range(100000))
print(sys.getsizeof(a), sys.getsizeof(b)) # 800056 800040
print(timeit.timeit('[1, 2, 3, 4, 5, 6, 7, 8, 9]')) # 0.07881959999999999
print(timeit.timeit('(1, 2, 3, 4, 5, 6, 7, 8, 9)')) # 0.010074500000000014
时间的结果仅供参考,根据运行代码的设备与环境都会导致不同,但是其大致差距可以看出。