09.Python 中元组完全指南

Python 中元组完全指南

本文档面向零基础新手,详细讲解 元组(tuple) 是什么、与列表的区别、元组解包、在实际项目中的用法(如配置文件),以及典型应用场景(函数返回多值、字典的键、解构赋值);并说明元组的“不可变”含义、元组内可变对象可修改、以及“给变量重新赋值”的用法。


第一部分:元组是什么?

一、元组的概念

元组 是 Python 里的一种有序、可重复的数据结构,和列表很像,但有一个根本区别:元组是不可变的——创建之后不能增、删、改元素。

基本写法:圆括号 () 把多个元素括起来,元素之间用逗号 , 分隔。

# 空元组
empty = ()
print(empty)   # ()

# 多个元素
point = (10, 20)
colors = ("红", "绿", "蓝")
mixed = (1, "hello", 3.14, True)
print(point, colors, mixed)

只有一个元素的元组: 必须在后面加逗号,否则括号会被当成运算括号。

# 错误:没有逗号时,(1) 只是整数 1
x = (1)
print(type(x))   # <class 'int'>

# 正确:单元素元组要加逗号
t = (1,)
print(type(t))   # <class 'tuple'>
print(t)         # (1,)

二、访问元组元素(索引与切片)

和列表一样,用索引取一个元素、用切片取一段。索引从 0 开始,-1 表示最后一个。

t = ("A", "B", "C", "D")
print(t[0])     # A
print(t[-1])    # D
print(t[1:3])   # ('B', 'C')(切片得到的是新元组)

三、元组没有“改、增、删”元素的方法

因为元组不可变,所以没有 append、insert、remove、pop 等方法,也不能用 元组[索引] = 新值 赋值。

t = (1, 2, 3)
# t[0] = 10      # 报错:TypeError
# t.append(4)     # 报错:元组没有 append
# t.remove(2)    # 报错:元组没有 remove

第二部分:元组 vs 列表

四、对比小结

项目 列表 list 元组 tuple
写法 [1, 2, 3] (1, 2, 3)
可变性 可增删改 不可变(不能增删改元素)
方法 append、insert、remove、sort 等 只有 count、index 等不修改自身的方法
适用场景 需要动态修改的序列 固定结构、不希望被改、作字典键等

何时用元组:

  • 数据不需要也不应该被修改(如坐标、配置项、函数返回的多个值)
  • 需要把序列当作字典的键(列表不能当键,元组可以)
  • 希望语义明确:“这是一组固定的值”

何时用列表:

  • 需要随时增删改元素时用列表。
# 坐标、RGB 等“固定一组值”适合元组
point = (100, 200)
rgb = (255, 0, 0)

# 待办事项、动态收集的数据适合列表
todos = ["写代码", "测试"]
todos.append("提交")

第三部分:元组解包(解构赋值)

五、什么是元组解包?

元组解包(也叫解构赋值)是指:把元组里的多个元素一次性赋给多个变量,左边变量个数要和元组元素个数一致(或用 * 收集多余元素)。

基本写法:

t = (10, 20)
a, b = t
print(a)   # 10
print(b)   # 20

等价于:a = t[0]; b = t[1],但更简洁。

常见写法:右边直接写元组(甚至省略括号)

# Python 中右边多个值用逗号隔开,本身就是元组
x, y = 10, 20
print(x, y)   # 10 20

name, age = "小明", 18
print(name, age)   # 小明 18

交换两个变量:

a, b = 1, 2
a, b = b, a
print(a, b)   # 2 1

*元素个数必须匹配(否则报错),除非用 收集:**

# a, b = (1, 2, 3)   # 报错:太多
# a, b, c = (1, 2)   # 报错:太少

# 用 * 把多余的元素收集成一个列表
first, *rest = (1, 2, 3, 4)
print(first)   # 1
print(rest)    # [2, 3, 4]

六、解包在循环中的应用

遍历“元组的列表”时解包:

points = [(1, 2), (3, 4), (5, 6)]
for x, y in points:
    print("x =", x, "y =", y)

遍历字典的 .items() 时解包:

d = {"name": "小明", "age": 18}
for key, value in d.items():
    print(key, value)

第四部分:元组用在实际项目中(如读取配置文件)

七、配置项、常量用元组表示

很多项目里会把“不会在运行中改动的配置”放在元组或元组组成的结构中,表示“只读”。

示例:简单配置(用元组表示一组选项或键)

# 允许的扩展名(固定集合)
ALLOWED_EXTENSIONS = ("jpg", "jpeg", "png", "gif")

# 默认配置项(名称, 默认值)成对
DEFAULT_CONFIG = (
    ("host", "localhost"),
    ("port", 8080),
    ("debug", False),
)

# 遍历配置
for name, value in DEFAULT_CONFIG:
    print(name, "=", value)

示例:从“配置文件结构”中读取(模拟)

# 模拟从配置文件读出的多组 (键, 值),用元组列表表示
config_items = [
    ("database.host", "127.0.0.1"),
    ("database.port", 3306),
    ("app.name", "MyApp"),
]
config = dict(config_items)   # 转成字典方便用
print(config["database.host"])   # 127.0.0.1

元组在这里的作用:每一行配置是 (键, 值) 的固定结构,用元组保证不被误改,且可哈希,必要时可作字典键。


第五部分:元组的典型应用场景

八、函数返回多个值

函数用 return 多个值 时,Python 会把这多个值打包成一个元组返回;接收时可以直接用元组解包。

def get_user():
    name = "小明"
    age = 18
    return name, age   # 相当于 return (name, age)

# 解包接收
user_name, user_age = get_user()
print(user_name, user_age)   # 小明 18

# 也可以整体接收为一个元组
info = get_user()
print(info)   # ('小明', 18)

九、字典的键

字典的必须不可变。列表可变,不能当键;元组不可变,可以当键(只要元组里的元素也都是不可变类型)。

# 用元组表示“坐标”作为键
location_names = {
    (0, 0): "原点",
    (1, 0): "东",
    (0, 1): "北",
}
print(location_names[(1, 0)])   # 东

# 列表不能当键
# bad = { [1,2]: "错误" }   # TypeError: unhashable type: 'list'

十、解构赋值(元组解包)作为典型用法

“解构赋值”本身就是元组的典型用法:多变量同时赋值、交换变量、在 for 中解包、用 * 收集多余元素等,前面已写,这里不再重复。


第六部分:元组不可变,但内部可变对象可被修改

十一、元组“不可变”指什么?

不可变 指的是:元组本身不能增删元素,也不能把某个位置改成另一个对象(不能 t[0] = 新值)。

但这不限制元组里某个元素如果是可变对象(如列表、字典),那个对象内部是可以被修改的。

t = (1, [2, 3], 4)
# t[0] = 10        # 报错:不能改元组里的“引用”
# t[1] = [5, 6]    # 报错:不能把 t[1] 换成别的对象

# 但 t[1] 指向的列表内部可以改
t[1].append(99)
print(t)   # (1, [2, 3, 99], 4)

理解: 元组里存的是“引用”(指向对象的指针)。元组不能改的是“这一格必须一直指向同一个对象”;对象本身若是列表,列表里的内容可以增删改。

再示例:元组里是字典

t = ({"a": 1},)
t[0]["b"] = 2   # 可以:改的是字典内部
print(t)        # ({'a': 1, 'b': 2},)

第七部分:不能修改元组的元素,但可以给变量重新赋值

十二、给“存储元组的变量”重新赋值

元组对象一旦创建就不能改,但变量可以随时指向新的对象。所以你可以让变量先指向一个元组,再让同一个变量指向另一个元组(或列表等)。

t = (1, 2, 3)
t = (4, 5, 6)   # 没有改原来的 (1,2,3),而是让 t 指向新元组
print(t)        # (4, 5, 6)

t = [1, 2, 3]   # 变量也可以改为指向列表
print(t)        # [1, 2, 3]

区别:

  • 不能做t[0] = 10(修改元组里的元素)→ 报错
  • 可以做t = (10, 20, 30)(让变量 t 指向新的元组)

第八部分:综合示例与小结

十三、综合示例

# 1. 元组创建与访问
point = (10, 20)
print(point[0], point[-1])

# 2. 元组解包
x, y = point
print(x, y)

# 3. 函数返回多值
def min_max(nums):
    return min(nums), max(nums)
lo, hi = min_max([3, 1, 4, 1, 5])
print(lo, hi)   # 1 5

# 4. 字典键用元组
d = {(1, 2): "A", (3, 4): "B"}
print(d[(1, 2)])

# 5. 元组内列表可修改
t = (1, [2, 3])
t[1].append(4)
print(t)   # (1, [2, 3, 4])

# 6. 变量可重新赋值为新元组
t = (1, 2)
t = (3, 4)
print(t)   # (3, 4)

十四、小结表

内容 要点
元组 () 表示,有序、可重复、不可变(不能增删改元素)
元组 vs 列表 列表可变、元组不可变;固定结构、键、多返回值等用元组
元组解包 a, b = 元组a, b = 值1, 值2;可配合 * 收集
实际项目 配置项、常量、键值对结构可用元组(或元组列表)表示
典型场景 函数返回多值、字典的键、解构赋值
不可变含义 不能改元组元素本身;若元素是列表/字典,其内部可改
变量赋值 不能 元组[i]=新值,但可以 变量 = 新元组

发表评论