Python元组(tuple)是有序、不可变的序列。外形上像用小括号写的列表,读下标、做切片的方式和列表几乎一样,但建好之后不能改其中的元素。坐标点、一组配置常量、函数一次交出来的多个返回值,这类数据更适合放进元组,减少被中途改掉的可能。
先建一个元组
最常见的写法是圆括号加逗号分隔。下面这个元组有三个整数,可以用下标读出某一项,也可以用 len 看长度:
t = (1, 2, 3)
print(t) # (1, 2, 3)
print(t[0]) # 1
print(len(t)) # 3元素不必同一类型,字符串、浮点数可以和整数放在一起。空元组写成 ()。只有一个元素时,逗号不能省:圆括号在表达式里本来就能当分组用,所以 (5) 算出来还是整数 5,必须写成 (5,) 解释器才认作元组。打包时甚至可以省略外层括号,逗号才是关键:
a = ()
b = (5,)
c = (1, "hello", 3.5)
d = 1, 2, 3
print(b, d) # (5,) (1, 2, 3)不可变意味着什么
试图给某个下标重新赋值,或调用列表才有的 append,都会直接报错。元组没有原地修改这一套接口:
t = (1, 2, 3)
# t[0] = 99 # TypeError
# t.append(4) # AttributeError真要改内容,常规做法是先 list(t) 转成列表,改完再用 tuple(...) 转回去,得到的是一份新元组,原来的 t 并没有被原地改写。
还有一层容易误会:不可变约束的是元组自己的槽位,不是槽位里指向的对象。若某个位置放的是列表,你仍可以往那个列表里 append,元组的长度和各位置指向谁没变,变的是列表内部。需要整份数据都锁死,就不要往元组里塞可变对象。
下标与切片
正下标从左边 0 起算,负下标从右边数,-1 是最后一项。切片同样是含头不含尾,步长写成负数还能倒序取出一个新元组:
t = (10, 20, 30, 40, 50)
print(t[0]) # 10
print(t[-1]) # 50
print(t[1:4]) # (20, 30, 40)
print(t[::-1]) # (50, 40, 30, 20, 10)切片得到的也是元组。因为不能对切片赋值来替换一段,这点和列表不同。
元组解包
左侧写多个名字、右侧给一个元组,解释器会按位置一一对应,这叫解包。交换两个变量时,右侧其实先打包成元组再解到左侧,所以能写成一行。函数里 return 3, 5 返回的就是元组,调用方照样解包接收:
point = (3, 5)
x, y = point
print(x, y) # 3 5
a, b = b, a
print(a, b)
def get_point():
return 3, 5
x, y = get_point()
print(x, y) # 3 5左右两边的个数必须一致,否则会报 ValueError。元素很多、只想抓头尾时,可以用 * 收剩余项,例如 first, *mid, last = t。
遍历与成员判断
for 可以直接遍历元组里的每一项。in 判断某个值是否出现,count / index 则分别统计次数和查找首次下标,用法和列表同名方法接近:
t = ("a", "b", "c")
for item in t:
print(item, end=" ") # a b c
print()
print("b" in t) # True
print(t.count("a")) # 1
print(t.index("c")) # 2元组和列表怎么选
| 特点 | 列表 list | 元组 tuple |
|---|---|---|
| 可变性 | 可变 | 不可变 |
| 语法 | 中括号 [] | 小括号 () 或省略 |
| 用途 | 数据还会增删改 | 当作固定记录 |
| 性能与键 | 稍慢 | 稍快,且可作字典键 |
选型可以记一条经验:还要往里追加、删除,就用列表。内容在逻辑上是一条写死的记录,或要拿去当字典的键,就用元组。元组可哈希,列表不可哈希,这是能不能当键的根本原因。
常见误区
- 单元素忘了逗号时,
(5)仍是整数,不是元组。 - 内容要调整时,先转列表再转回元组,而不是对下标硬赋值。
- 元组里如果嵌了列表,内部列表仍可变,锁住的只是元组自身那一层结构。