RSS
菜单
全部文章快讯开发科技深度热点

列表、元组、字典、集合(Python 从精通到入门 · 27)

内容摘要

四种容器,四种性格:列表能改、元组锁定、字典查得快、集合专治重复。选对了容器,代码就顺了一半。

四种容器,四种性格:列表能改、元组锁定、字典查得快、集合专治重复。选对了容器,代码就顺了一半。

单个变量只能存一个值。要存一批数据,就需要容器。Python 内置的四种容器各有各的脾气,这一篇一次讲完。

你将学到

  • 列表的增删改查与切片,sort 与 sorted 的区别
  • 元组与解包,为什么需要不可变的序列
  • 字典的键值操作,get / items / keys / values 与遍历
  • 集合的去重与交并差
  • 四种容器怎么选
  • 嵌套数据结构初识

前置知识

先读 上一篇:字符串与格式化。

列表 list:有序、可变

fruits = ["苹果", "香蕉", "橘子"]
print(fruits[0])     # 输出: 苹果
print(fruits[-1])    # 输出: 橘子
print(len(fruits))   # 输出: 3

增:append / insert / extend

fruits = ["苹果", "香蕉"]
fruits.append("橘子")          # 末尾追加一个
fruits.insert(0, "西瓜")        # 在下标 0 处插入
fruits.extend(["葡萄", "梨"])   # 一次追加多个
print(fruits)
# 输出: ['西瓜', '苹果', '香蕉', '橘子', '葡萄', '梨']

删:remove / pop / del

nums = [10, 20, 30, 20]
nums.remove(20)      # 删除第一个值为 20 的元素
print(nums)          # 输出: [10, 30, 20]

last = nums.pop()    # 弹出最后一个,并返回它
print(last, nums)    # 输出: 20 [10, 30]

del nums[0]          # 用 del 按下标删
print(nums)          # 输出: [30]

改:直接赋值 + 切片赋值

nums = [1, 2, 3, 4, 5]
nums[0] = 100
nums[1:3] = [20, 30, 40]   # 切片赋值,长度可以不同
print(nums)                # 输出: [100, 20, 30, 40, 4, 5]

查:索引、切片、in

nums = [10, 20, 30, 40, 50]
print(nums[1:4])         # 输出: [20, 30, 40]
print(30 in nums)        # 输出: True
print(nums.index(30))    # 输出: 2

排序:sort 与 sorted(最易混的一对)

nums = [3, 1, 4, 1, 5]

nums.sort()              # 原地排序,返回 None,会改原列表
print(nums)              # 输出: [1, 1, 3, 4, 5]

nums = [3, 1, 4, 1, 5]
new = sorted(nums)       # 返回新列表,原列表不动
print(new, nums)         # 输出: [1, 1, 3, 4, 5] [3, 1, 4, 1, 5]
print(sorted(nums, reverse=True))   # 输出: [5, 4, 3, 1, 1]
print(sorted(["bb", "a", "ccc"], key=len))   # 按长度排: ['a', 'bb', 'ccc']

元组 tuple:有序、不可变

元组用小括号,一旦创建就不能改。

point = (3, 4)
print(point[0], len(point))   # 输出: 3 2
# point[0] = 10    # ❌ 不可变,TypeError

单元素元组要加逗号,否则只是个带括号的值:

t1 = (5)      # 这是整数 5,不是元组!
t2 = (5,)     # ✅ 这才是单元素元组
print(type(t1), type(t2))   # 输出: <class 'int'> <class 'tuple'>

解包

point = (3, 4)
x, y = point
print(x, y)      # 输出: 3 4

def min_max(nums):
    return min(nums), max(nums)   # 函数返回多值其实就是返回元组
low, high = min_max([5, 2, 8])
print(low, high)   # 输出: 2 8

first, *rest = [1, 2, 3, 4]   # 用 * 收集剩余
print(first, rest)            # 输出: 1 [2, 3, 4]

为什么需要不可变

  • 可以安全地作为字典的键、集合的元素。
  • 多线程共享时不用担心被改。
  • 语义上表达"这组值不该变",比如坐标、RGB 颜色。
locations = {(0, 0): "原点", (1, 2): "点A"}   # 元组能当字典的键
print(locations[(0, 0)])   # 输出: 原点

字典 dict:键值对

字典存"键 → 值"的映射,查起来很快。

person = {"name": "小明", "age": 18, "city": "北京"}
print(person["name"], len(person))   # 输出: 小明 3

增删改

person = {"name": "小明"}
person["age"] = 18          # 新增键
person["name"] = "小明同学"  # 修改已有的键
del person["age"]           # 删除键
print(person)               # 输出: {'name': '小明同学'}

get:安全取值

用 [] 取不存在的键会报 KeyError,get 不会:

person = {"name": "小明"}
# print(person["age"])       # ❌ KeyError: 'age'
print(person.get("age", 0))   # 输出: 0    不存在时给默认值

实践建议:不确定键存不存在时,用 get。

遍历与判断

person = {"name": "小明", "age": 18}
print(list(person.keys()), list(person.values()))   # 输出: ['name', 'age'] ['小明', 18]

for key, value in person.items():    # 同时拿到键和值(最常用)
    print(f"{key} = {value}")
# 输出: name = 小明 / age = 18

print("name" in person)        # 输出: True

# 字典合并(Python 3.9+)
print({"x": 1} | {"y": 2})     # 输出: {'x': 1, 'y': 2}

集合 set:无序、不重复

集合最擅长两件事:去重和做集合运算。

nums = [1, 2, 2, 3, 3, 3]
print(set(nums))   # 输出: {1, 2, 3}(顺序可能不同,集合无序)

添加与删除

s = {1, 2, 3}
s.add(4)
print(s)          # 输出: {1, 2, 3, 4}
s.discard(2)      # 删除,不存在也不报错
print(s)          # 输出: {1, 3, 4}

交、并、差

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a & b)      # 输出: {3, 4}               交集
print(a | b)      # 输出: {1, 2, 3, 4, 5, 6}   并集
print(a - b)      # 输出: {1, 2}               差集(在 a 不在 b)
print(a ^ b)      # 输出: {1, 2, 5, 6}         对称差(只在一方)

快判断成员 / 去重

names = ["小明", "小红", "小明"]
print(list(set(names)))   # 输出: ['小明', '小红'](顺序不定)

# 集合的 in 判断是 O(1),比列表快很多(如 set(range(1000000)) 查成员几乎瞬间)

# ⚠️ 空集合只能写 set(),{} 是空字典
print(type({}), type(set()))   # 输出: <class 'dict'> <class 'set'>

四种容器怎么选

容器 有序 可变 重复元素 典型用途
list 是 是 允许 一串有序数据
tuple 是 否 允许 不该变的记录、字典键
dict 是(3.7+) 是 键唯一 键值映射、快速查找
set 否 是 不允许 去重、集合运算、成员判断
shopping = ["牛奶", "面包"]      # 要顺序、要能改 → list
rgb = (255, 128, 0)              # 固定的一组值 → tuple
phone = {"小明": "13800000000"}  # 按名字查东西 → dict
tags = {"python", "教程"}        # 去重或判断"在不在" → set

嵌套数据结构初识

容器的元素还可以是容器,形成"结构":

students = [
    {"name": "小明", "scores": [90, 85, 88]},
    {"name": "小红", "scores": [95, 92, 99]},
]
for student in students:
    avg = sum(student["scores"]) / len(student["scores"])
    print(f"{student['name']} 平均分 {avg:.1f}")
# 输出: 小明 平均分 87.7 / 小红 平均分 95.3

这就是 JSON、配置文件的常见形态,后面 16-数据处理 会大量用到。

常见坑

坑一:赋值不是复制

a = [1, 2, 3]
b = a            # b 和 a 指向同一个列表!
b.append(4)
print(a)         # 输出: [1, 2, 3, 4]   a 也被改了

# ✅ 想要副本用 copy 或切片
b = a.copy()     # 或 b = a[:]
b.append(5)
print(a)         # 输出: [1, 2, 3, 4]

坑二:sort 返回 None

# ❌ sort 原地排序,返回值是 None
# result = nums.sort()    # result 是 None

# ✅ 要么原地排序不看返回值,要么用 sorted 拿新列表
nums = [3, 1, 2]
nums.sort()
result = sorted(nums)

坑三:用可变对象做字典键

# ❌ 列表不可哈希,不能当键:TypeError: unhashable type: 'list'
# d = {[1, 2]: "x"}

# ✅ 用元组
d = {(1, 2): "x"}
print(d[(1, 2)])   # 输出: x

坑四:误以为集合有序

s = {"b", "a", "c"}
print(s)           # 输出顺序不确定,别依赖
print(sorted(s))   # 输出: ['a', 'b', 'c']   需要有序就排序

小结

  • list 有序可变,append / insert / remove / pop 是高频操作。
  • sort 原地排序返回 None;sorted 返回新列表。别记反了。
  • tuple 不可变,解包和"当字典键"是它的招牌。
  • dict 存键值对,取不存在的键用 get 更安全;items() 遍历最常用。
  • set 无序不重复,擅长去重和交并差;空集合写 set()。
  • 选择容器看三点:要不要顺序、要不要能改、要不要去重。
  • b = a 只是起别名,要独立副本请用 .copy() 或切片。
  • 嵌套容器(列表套字典等)是真实数据的常见形态。

延伸阅读

  • 21-推导式与函数式工具:用一行搞定列表生成与筛选
  • 16-数据处理:json / csv / dataclasses:容器在真实数据里的用法

上一篇:字符串与格式化 · 下一篇:你好世界与第一个程序

— 全文完 —回到顶部 ↑
下载推广海报

文章推广海报

《列表、元组、字典、集合(Python 从精通到入门 · 27)》完整推广海报
DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。