【Python】元组
元组
元组基本概念
元组(Tuple)是 Python 中的一种有序、不可变(immutable)的序列类型,用于存储一组元素。
- “有序”意味着元组中的元素按添加顺序排列,可以通过索引访问。
- “不可变”意味着元组创建后,其内部的元素不能被修改、删除或添加。
用途
- 用于存储固定的数据集合,例如日期(年、月、日)、RGB 颜色值、坐标点等。
- 可以作为字典的键(因为元组是不可变的),而列表不能。
- 元组操作通常比列表更高效,适合不需要修改的场景。
Python 元组是一系列逗号分隔的项目,括在括号中 ()。Python 元组中的项目不需要具有相同的数据类型。
以下是 Python 元组的一些示例:
tup1 = ("Rohan", "Physics", 21, 69.75)
tup2 = (1, 2, 3, 4, 5)
tup3 = ("a", "b", "c", "d")
tup4 = (25.50, True, -55, 1+2j)
空元组写成两个括号,不包含任何内容:
tup1 = ();
要编写包含单个值的元组,即使只有一个值,也必须包含一个逗号:
tup1 = (50,);
创建元组
使用小括号 () —— 最常见方式
t = (1, 2, 3, 4)
print(t) # (1, 2, 3, 4)
print(type(t)) # <class 'tuple'>
特点:
- 元素可以是任意类型(数字、字符串、布尔、列表、元组等)。
- 推荐方式,最直观。
不加括号,直接用逗号分隔
t = 1, 2, 3, 4
print(t) # (1, 2, 3, 4)
print(type(t)) # <class 'tuple'>
重点:Python 中,只要有逗号,就会生成元组。括号只是帮助我们更清晰地表示。
创建单元素元组
容易出错的地方
t1 = (5,) # 正确,单元素元组
t2 = (5) # 错误,这是 int 类型
t3 = 5, # 正确,不加括号也行
原因:
- Python 里
(5)会被当作数学运算中的括号,结果就是整数5。 - 只有加上逗号
(5,),才会被识别为元组。
创建空元组
t = ()
print(t) # ()
print(type(t)) # <class 'tuple'>
通常用于初始化,后续再替换。
使用 tuple() 构造函数
可以把其他可迭代对象转换为元组:
# 列表转元组
t1 = tuple([1, 2, 3])
print(t1) # (1, 2, 3)
# 字符串转元组
t2 = tuple("abc")
print(t2) # ('a', 'b', 'c')
# range 转元组
t3 = tuple(range(5))
print(t3) # (0, 1, 2, 3, 4)
# 字典转元组(只取 key)
t4 = tuple({"a":1, "b":2})
print(t4) # ('a', 'b')
嵌套元组
元组中可以再包含元组(或其他对象):
t = (1, (2, 3), (4, 5, 6))
print(t) # (1, (2, 3), (4, 5, 6))
print(t[1][0]) # 2
这在存储二维/多维数据时很常用,比如矩阵、坐标点集。
从函数返回多个值
函数可以“同时返回多个值”,其实就是返回一个元组:
def get_point():
return 10, 20
point = get_point()
print(point) # (10, 20)
x, y = get_point()
print(x, y) # 10 20
这也是 Python 元组的常见应用场景。
元组创建的注意点
-
小括号可省略,但建议保留,增加可读性。
-
单元素元组必须带逗号
(x,),否则不是元组。 -
不可变但可以包含可变对象:
t = (1, [2, 3]) t[1][0] = 100 print(t) # (1, [100, 3])元组本身不可变,但内部可变对象的内容可以修改。
访问元组项目
元组(tuple)是有序不可变序列:每个元素在元组中都有唯一的位置(索引),但不能修改。
访问(Access)操作:就是根据索引、切片、解包等方式,读取其中的数据,而不是修改。
索引(Indexing)
- 正索引:从左到右,
0开始。 - 负索引:从右到左,
-1表示最后一个。
t1 = ("Rohan", "Physics", 21, 69.75)
t2 = (1, 2, 3, 4, 5)
print(t1[0]) # Rohan
print(t2[2]) # 3
# 负索引
t3 = ("a", "b", "c", "d")
print(t3[-1]) # d
print(t3[-3]) # b
切片(Slicing)
- 语法:
tuple[start:stop:step] - 特点:返回新的子元组,不会修改原元组。
t = (0, 1, 2, 3, 4, 5)
print(t[1:4]) # (1, 2, 3) 从索引1到3
print(t[:3]) # (0, 1, 2) 省略 start,默认0
print(t[3:]) # (3, 4, 5) 省略 stop,默认到结尾
print(t[::2]) # (0, 2, 4) 步长为2
print(t[::-1]) # (5, 4, 3, 2, 1, 0) 倒序
注意:切片的 stop 不包含 对应索引。
使用负索引进行切片
t = ("a", "b", "c", "d", "e")
print(t[-3:]) # ('c', 'd', 'e') 从倒数第3个到最后
print(t[1:-1]) # ('b', 'c', 'd') 去掉首尾
子元组(Subtuple)
子元组就是通过切片获取的一部分元组。
tuple1 = ("a", "b", "c", "d")
tuple2 = (25.50, True, -55, 1+2j)
print(tuple1[1:3]) # ('b', 'c')
print(tuple2[0:2]) # (25.5, True)
遍历访问
元组是可迭代对象,可以逐一访问:
t = ("apple", "banana", "cherry")
# 只取元素
for item in t:
print(item)
# 同时取索引和元素
for i, v in enumerate(t):
print(i, v)
解包(Unpacking)
一次性把元组的元素取出来,赋值给多个变量:
t = ("Tom", 18, "Physics")
name, age, subject = t
print(name, age, subject) # Tom 18 Physics
# 带 *
nums = (1, 2, 3, 4, 5)
a, *b = nums
print(a) # 1
print(b) # [2, 3, 4, 5]
访问嵌套元组
元组里还能套元组,需要多级索引。
t = (1, (2, 3), (4, (5, 6)))
print(t[1]) # (2, 3)
print(t[1][0]) # 2
print(t[2][1][1]) # 6
index():获取元素位置
t = ("a", "b", "c", "b")
print(t.index("b")) # 1
print(t.index("b", 2)) # 3 从索引2开始查找
count():统计元素出现次数
t = (1, 2, 2, 3, 2, 4)
print(t.count(2)) # 3
len():获取长度
t = (10, 20, 30)
print(len(t)) # 3
print(t[len(t)-1]) # 30,最后一个元素
注意事项
-
不可变性:元组不能修改元素值,但如果内部有 可变对象(如 list),则能改。
t = (1, [2, 3]) t[1][0] = 99 print(t) # (1, [99, 3]) -
越界会报错:
t = (1, 2, 3) print(t[5]) # IndexError -
解包必须匹配数量,除非用
*。t = (1, 2, 3) a, b = t # ❌ ValueError
更新元组
元组(tuple)是不可变的序列类型。
- 一旦创建,不能直接修改、添加或删除元素。
- 如果需要“更新”,只能通过 重建新的元组 来实现。
所谓“更新元组”,实际上是:
- 组合(concatenate):把多个元组拼接成新元组。
- 切片(slice)+拼接:用切片截取部分,再插入新元素。
- 转换为列表修改:借助列表的可变性修改,再转回元组。
- 推导式/解包:用 Python 特性生成新的元组。
使用 串连接运算符 +
T1 = (10, 20, 30, 40)
T2 = ('one', 'two', 'three', 'four')
# 通过拼接生成新元组
T1 = T1 + T2
print(T1)
输出:
(10, 20, 30, 40, 'one', 'two', 'three', 'four')
适合在元组末尾增加新元素。
注意:这会创建一个新元组,而不是修改原元组。
使用 切片 + 拼接
T1 = (37, 14, 95, 40)
new_elements = ('green', 'blue', 'red', 'pink')
# 切片 + 拼接
updated_tuple = T1[:2] + new_elements + T1[2:]
print("Original:", T1)
print("Updated:", updated_tuple)
输出:
Original: (37, 14, 95, 40)
Updated: (37, 14, 'green', 'blue', 'red', 'pink', 95, 40)
适合在指定位置插入元素。
使用 列表推导式(list comprehension)
T1 = (10, 20, 30, 40)
# 转成列表并更新
updated_list = [item + 100 for item in list(T1)]
updated_tuple = tuple(updated_list)
print("Original:", T1)
print("Updated:", updated_tuple)
输出:
Original: (10, 20, 30, 40)
Updated: (110, 120, 130, 140)
适合批量更新元组里的元素。
使用 append()(间接)
T1 = (10, 20, 30, 40)
new_elements = [50, 60, 70]
# 转换为列表后用 append()
list_T1 = list(T1)
for element in new_elements:
list_T1.append(element)
updated_tuple = tuple(list_T1)
print("Original:", T1)
print("Updated:", updated_tuple)
输出:
Original: (10, 20, 30, 40)
Updated: (10, 20, 30, 40, 50, 60, 70)
适合多个元素逐一添加。
使用 解包(unpacking)
T = (1, 2, 3, 4)
# 修改第一个元素
T = (100, *T[1:])
print(T) # (100, 2, 3, 4)
直观地替换某个位置的值。
使用生成器表达式生成新元组
T = (1, 2, 3, 4, 5)
# 生成每个元素平方的新元组
T = tuple(x**2 for x in T) # x**2 for x in T 是一个生成器表达式,需要转换为元组类型
print(T) # (1, 4, 9, 16, 25)
元组中含有可变对象(间接更新)
T = (1, [2, 3], 4)
# 修改元组中的列表元素
T[1][0] = 200
print(T) # (1, [200, 3], 4)
虽然元组不可变,但里面的可变对象(列表、字典)可以被修改。
元组解包
什么是解包?
- 解包(unpacking):把元组(或其他可迭代对象)中的元素“拆开”,分别赋值给多个变量。
- 打包(packing):把多个值组合成一个元组。
示例:
t1 = (10, 20) # 元组写法 1
t2 = 10, 20 # 元组写法 2(括号可省略)
print(type(t1)) # <class 'tuple'>
print(type(t2)) # <class 'tuple'>
基础解包
tup1 = (10, 20, 30)
x, y, z = tup1
print("x:", x, "y:", y, "z:", z)
# 输出: x: 10 y: 20 z: 30
要点:左侧变量数量必须和右侧元组元素数量相等。
解包时报错(ValueError)
如果变量个数不匹配,就会报错:
tup1 = (10, 20, 30)
x, y = tup1
# ValueError: too many values to unpack (expected 2)
x, y, p, q = tup1
# ValueError: not enough values to unpack (expected 4, got 3)
使用 * 号进行灵活解包
Python 允许在解包时用 *变量 接收“剩余元素”,避免报错。
接收到的结果会是一个 列表。
-
接收剩余元素
tup1 = (10, 20, 30) x, *y = tup1 print("x:", x, "y:", y) # 输出: x: 10 y: [20, 30] -
左右两边都解包
tup1 = (10, 20, 30, 40, 50, 60) x, *y, z = tup1 print("x:", x, "y:", y, "z:", z) # 输出: x: 10 y: [20, 30, 40, 50] z: 60 -
前面用
*tup1 = (10, 20, 30, 40, 50, 60) *x, y, z = tup1 print("x:", x, "y:", y, "z:", z) # 输出: x: [10, 20, 30, 40] y: 50 z: 60
嵌套解包
t = (1, (2, 3), 4)
a, (b, c), d = t
print(a, b, c, d) # 1 2 3 4
解包忽略值(用 _ 占位)
tup = (10, 20, 30)
x, _, z = tup
print(x, z) # 10 30
解包在实际中的应用
-
交换变量
a, b = 1, 2 a, b = b, a print(a, b) # 2 1 -
遍历时同时解包
pairs = [(1, 'a'), (2, 'b')] for num, char in pairs: print(num, char) -
解压(zip 与解包)
pairs = [(1, 'a'), (2, 'b'), (3, 'c')] nums, letters = zip(*pairs) print(nums) # (1, 2, 3) print(letters) # ('a', 'b', 'c')
循环元组
元组是 可迭代对象(iterable),这意味着我们可以使用循环(如 for)逐个访问其中的元素。
常见用途:
- 遍历元组中的所有元素;
- 遍历时解包多个值;
- 搭配
enumerate()获取索引和值; - 搭配
zip()同时遍历多个元组。
基础循环:遍历整个元组
tup = ("apple", "banana", "cherry")
for item in tup:
print(item)
输出:
apple
banana
cherry
和列表一样,元组遍历的顺序是 从左到右,保持元素的 有序性。
使用索引循环(range(len()))
有时我们需要访问 索引:
tup = ("apple", "banana", "cherry")
for i in range(len(tup)):
print("Index:", i, "Value:", tup[i])
输出:
Index: 0 Value: apple
Index: 1 Value: banana
Index: 2 Value: cherry
使用 enumerate() 同时取索引和值
这是更 Pythonic 的写法:
tup = ("apple", "banana", "cherry")
for index, value in enumerate(tup):
print(f"Index {index} -> {value}")
输出:
Index 0 -> apple
Index 1 -> banana
Index 2 -> cherry
循环时解包元组
当元组本身嵌套多个元素时,可以 直接解包:
students = [("Tom", 20), ("Alice", 22), ("Bob", 19)]
for name, age in students:
print(f"{name} is {age} years old")
输出:
Tom is 20 years old
Alice is 22 years old
Bob is 19 years old
while 循环遍历元组
虽然 for 更常用,但 while 也能遍历:
tup = ("a", "b", "c", "d")
i = 0
while i < len(tup):
print(tup[i])
i += 1
索引变量在循环中使用,以跟踪序列中的当前位置或索引,例如元组或数组。它通常在循环之前初始化,并在循环中更新以迭代序列。
使用 zip() 同时循环多个元组
names = ("Tom", "Alice", "Bob")
ages = (20, 22, 19)
for name, age in zip(names, ages):
print(f"{name} -> {age}")
输出:
Tom -> 20
Alice -> 22
Bob -> 19
循环中的 break 与 continue
tup = (10, 20, 30, 40, 50)
for num in tup:
if num == 30:
continue # 跳过 30
if num == 50:
break # 遇到 50 停止循环
print(num)
输出:
10
20
40
嵌套元组的循环
matrix = ((1, 2), (3, 4), (5, 6))
for row in matrix:
for col in row:
print(col, end=" ")
print()
输出:
1 2
3 4
5 6
all() 与 any() 搭配循环
tup = (2, 4, 6, 8)
print(all(x % 2 == 0 for x in tup)) # True(全是偶数)
print(any(x > 5 for x in tup)) # True(至少一个大于5)
sorted() 遍历
tup = (3, 1, 4, 2)
for x in sorted(tup):
print(x, end=" ")
# 输出: 1 2 3 4
加入元组
元组是不可变(immutable)的,也就是说一旦创建,它的内容(元素的数量和顺序)就不能被直接修改。因此,元组没有像 list.append() 或 list.extend() 这样的直接方法。
元组的不可变性保证了:
- 元组可以作为字典的键;
- 元组可以作为集合的元素;
- 提高数据的安全性和哈希性能。
所以 不能直接增删改元组的元素,但我们可以 通过生成新元组来实现“加入”效果。
用 + 运算符连接元组(最常见)
示例:
tup = (1, 2, 3)
tup = tup + (4,) # 注意 (4,) 必须加逗号,才能表示元组
print(tup)
输出:
(1, 2, 3, 4)
使用 += 运算符
其实和 + 类似,本质上也是创建了新元组。
示例:
tup = (1, 2, 3)
tup += (4, 5)
print(tup)
输出:
(1, 2, 3, 4, 5)
使用 tuple() 和列表转换(灵活)
如果你要频繁“加入元素”,建议先把元组转为列表,操作完成后再转回元组。
示例:
tup = (1, 2, 3)
temp_list = list(tup)
temp_list.append(4) # 列表支持 append
tup = tuple(temp_list)
print(tup)
输出:
(1, 2, 3, 4)
适用场景:需要多次修改时,比频繁用
+效率更高。
使用 * 解包方式加入元素(灵活可控)
解包 (*) 可以让你把一个元组拆开,再与新元素组合。
示例:
tup = (1, 2, 3)
tup = (*tup, 4, 5) # 在末尾加入
print(tup)
输出:
(1, 2, 3, 4, 5)
也可以插入到开头:
tup = (1, 2, 3)
tup = (0, *tup)
print(tup)
输出:
(0, 1, 2, 3)
使用 sum() 函数
sum() 通常用于数值相加,但加元组时也能“拼接”,不过需要指定起始值 ()。
T1 = (10, 20)
T2 = (30, 40)
T3 = (50, 60)
joined = sum((T1, T2, T3), ())
print(joined)
输出:
(10, 20, 30, 40, 50, 60)
注意:sum() 内部会做大量拷贝,效率比不上 + 或 *,所以不推荐在大数据下使用。
使用 for 循环逐个加入
通过循环遍历一个元组的元素,用 += 拼接到另一个元组。
T1 = (10, 20)
T2 = (30, 40)
for item in T2:
T1 += (item,)
print(T1)
输出:
(10, 20, 30, 40)
适用场景:理解拼接原理,但实际效率不高。
在指定位置插入元素
虽然没有直接的 insert,但可以通过切片和拼接实现。
示例:
tup = (1, 2, 3, 4)
pos = 2 # 想在下标 2 的位置插入 99
tup = tup[:pos] + (99,) + tup[pos:]
print(tup)
输出:
(1, 2, 99, 3, 4)
一次性加入多个元素
无论是 + 还是 * 解包,都可以一次性加入多个元素。
示例:
tup = (1, 2, 3)
tup = tup + (4, 5, 6)
print(tup)
输出:
(1, 2, 3, 4, 5, 6)
使用生成器生成新元组
虽然元组推导式不存在,但可以用生成器表达式再转成元组,顺便加上新元素。
示例:
tup = (1, 2, 3)
new_tup = tuple(x for x in tup) + (4,)
print(new_tup)
输出:
(1, 2, 3, 4)
元组方法
元组概述
- 元组(
tuple) 是 Python 的基本数据结构之一,是一种 有序、不可变(immutable)的序列类型。 - 与 列表(list) 不同,元组一旦创建就 无法修改(不能增删元素),因此非常适合表示 固定的数据集合。
- 元组的不可变性在 数据安全性与稳定性 很重要的场景下非常有用,比如:
- 表示一个 坐标点
(x, y); - 作为 字典的键(需要可哈希对象);
- 表示函数的 多返回值。
- 表示一个 坐标点
元组可以包含 不同数据类型:整数、浮点数、字符串,甚至其他元组。
查看元组支持的方法
可以通过 dir() 和 help() 探索元组支持的所有方法与属性:
print(dir((1, 2)))
print(help((1, 2).index))
输出(截取关键部分):
['__add__', '__class__', ..., 'count', 'index']
Help on built-in function index:
index(value, start=0, stop=9223372036854775807, /)
结论:元组真正提供的 可直接调用的方法只有 2 个:
tuple.count(obj)tuple.index(obj)
元组方法详解
-
tuple.count(obj)-
功能:返回指定对象在元组中出现的次数。
-
语法:
tuple.count(obj) -
返回值:整数,表示出现次数。
示例 1:基本用法
tup1 = (10, 20, 45, 10, 30, 10, 55) print("Tup1:", tup1) c = tup1.count(10) print("count of 10:", c)输出:
Tup1: (10, 20, 45, 10, 30, 10, 55) count of 10: 3示例 2:包含表达式的情况
tup1 = (10, 20/80, 0.25, 10/40, 30, 10, 55) print("Tup1:", tup1) c = tup1.count(0.25) print("count of 0.25:", c)输出:
Tup1: (10, 0.25, 0.25, 0.25, 30, 10, 55) count of 0.25: 3 -
-
tuple.index(obj[, start[, end]])-
功能:返回指定对象在元组中首次出现的索引。
-
语法:
tuple.index(obj, start=0, end=len(tuple)) -
返回值:整数,表示元素第一次出现的位置。
-
异常:如果元素不存在,则抛出
ValueError。
示例:
tup1 = (25, 12, 10, -21, 10, 100) print("Tup1:", tup1) x = tup1.index(10) print("First index of 10:", x)输出:
Tup1: (25, 12, 10, -21, 10, 100) First index of 10: 2示例(指定起始索引):
tup = ('a','b','c','b','d') print(tup.index('b', 2)) # 从索引 2 开始找输出:
3 -
虽然元组只有 2 个方法,但由于它实现了 序列协议,所以我们还能用很多内置函数和操作符:
| 操作 | 示例 | 说明 |
|---|---|---|
| 索引 | t[0] |
访问单个元素 |
| 切片 | t[1:3] |
获取子元组 |
| 拼接 | t1 + t2 |
返回新元组 |
| 重复 | t * 3 |
元组重复 |
| 成员测试 | x in t |
判断元素是否存在 |
| 长度 | len(t) |
获取长度 |
| 迭代 | for x in t: |
遍历元素 |
| 解包 | a, b = (1, 2) |
多值赋值 |
| 带星号解包 | a, *b, c = (1,2,3,4) |
剩余部分收集为列表 |
| 排序 | sorted(t) |
返回排序后的 列表 |
| 统计 | min(t), max(t), sum(t) |
求最值、总和 |
命名元组
什么是 NamedTuple
namedtuple是 Python collections 模块中的一个工厂函数,用于创建 带字段名的元组子类。- 它结合了元组的不可变性和字典的可读字段:
- 可以像元组一样 索引访问;
- 可以像对象一样 通过字段名访问。
优势
- 可读性高:可以通过字段名访问,而不是记住索引;
- 占用内存小:比字典更轻量;
- 不可变:保证数据安全;
- 兼容元组操作:可进行切片、索引等操作。
导入与创建 NamedTuple
-
导入
from collections import namedtuple -
创建命名元组
语法:
NamedTupleClass = namedtuple('ClassName', ['field1', 'field2', ...])'ClassName':命名元组类名(首字母大写惯例);['field1', 'field2', ...]:字段名列表(也可用空格分隔的字符串)。
示例:
from collections import namedtuple # 定义一个二维坐标类 Point Point = namedtuple('Point', ['x', 'y']) # 创建实例 p = Point(10, 20) print(p) # Point(x=10, y=20) print(p.x, p.y) # 10 20注意:字段名不能是 Python 保留关键字,否则可加参数
_rename=True自动重命名。
访问 NamedTuple 字段
-
通过字段名
print(p.x) # 10 print(p.y) # 20 -
通过索引
print(p[0]) # 10 print(p[1]) # 20 -
使用
getattr()print(getattr(p, 'x')) # 10 print(getattr(p, 'y')) # 20 -
遍历
for value in p: print(value)
NamedTuple 内置方法
命名元组除了普通元组的方法,还带有一些专用方法:
| 方法 | 功能 | 示例 |
|---|---|---|
_fields |
返回字段名元组 | Point._fields → ('x', 'y') |
_make(iterable) |
从可迭代对象创建实例 | Point._make([30, 40]) → Point(x=30, y=40) |
_asdict() |
转换为字典 | p._asdict() → {'x': 10, 'y': 20} |
_replace(**kwargs) |
替换字段创建新实例 | p._replace(x=100) → Point(x=100, y=20) |
示例:
# _fields
print(p._fields) # ('x', 'y')
# _make
p2 = Point._make([30, 40])
print(p2) # Point(x=30, y=40)
# _asdict
print(p._asdict()) # {'x': 10, 'y': 20}
# _replace
p3 = p._replace(x=50)
print(p3) # Point(x=50, y=20)
使用 ** 运算符
** 运算符可以将命名元组的字段解压缩成关键字参数,用于函数调用或创建命名元组。
示例:
Student = namedtuple('Student', ['name', 'age', 'DOB'])
di = {'name': "ravi", 'age': 24, 'DOB': '13-9-1997'}
s = Student(**di)
print(s) # Student(name='ravi', age=24, DOB='13-9-1997')
其他用法
-
默认值
Person = namedtuple('Person', ['name', 'age', 'city'], defaults=['Unknown']) p1 = Person('Alice') print(p1) # Person(name='Alice', age='Unknown', city='Unknown') -
嵌套命名元组
Point3D = namedtuple('Point3D', ['x', 'y', 'z']) Line = namedtuple('Line', ['start', 'end']) line = Line(Point3D(0,0,0), Point3D(1,1,1)) print(line.start.x) # 0 print(line.end.z) # 1 -
配合函数返回多个值
def get_point(): return Point(5, 10) pt = get_point() print(pt.x, pt.y) # 5 10
更多推荐


所有评论(0)