前言

Python 写得好不好,一半看数据结构选得对不对。内置的四大金刚——列表、元组、字典、集合——覆盖了日常 95% 的场景。

一、列表:有序可变序列

# 创建
nums = [1, 2, 3]
mixed = [1, "hello", True, [4, 5]]     # 可以混装类型

# 索引与切片
nums[0]          # 1
nums[-1]         # 3(负数从尾部数)
nums[0:2]        # [1, 2]
nums[::-1]       # [3, 2, 1] 反转

# 增删改
nums.append(4)           # 尾部追加: [1,2,3,4]
nums.insert(0, 0)        # 指定位置插入
nums.extend([5, 6])      # 拼接另一个列表
nums.pop()               # 弹出尾部元素
nums.pop(0)              # 弹出指定下标
nums.remove(3)           # 按值删除(只删第一个匹配)
del nums[0]              # 按下标删除

# 常用操作
len(nums)                # 长度
sorted(nums, reverse=True)
max(nums), min(nums), sum(nums)
1 in nums                # 成员判断(列表是 O(n))
nums.index(2)            # 查下标
nums.count(2)            # 计数

⚠️ 经典坑:b = a 只是引用同一个列表,改 b 会影响 a。要复制用 a.copy() 或 a[:]。

二、元组:不可变序列

point = (3, 5)
x, y = point             # 解包(很常用!)
a, b = b, a              # 交换变量

# 单元素元组必须带逗号
t = (42,)                # ✅ 元组
t = (42)                 # ❌ 这只是个 int

# 不可变 = 可哈希 = 能当字典的 key、能进集合
locations = {(30.5, 114.3): "wuhan"}

函数返回多个值,本质就是返回元组:

def min_max(nums):
    return min(nums), max(nums)

lo, hi = min_max([3, 1, 4, 1, 5])

三、字典:键值对映射

user = {"name": "zy", "level": 5, "tags": ["linux", "go"]}

# 读写
user["name"]                    # 'zy'
user.get("email")               # None(不抛 KeyError)
user.get("email", "未填写")      # 带默认值
user["email"] = "zy@x.cn"       # 新增/修改
del user["email"]               # 删除

# 安全访问嵌套结构
conf = {"server": {"port": 8080}}
port = conf.get("server", {}).get("port", 80)

# 遍历
for k, v in user.items():
    print(f"{k} = {v}")

# 合并(3.9+)
defaults = {"debug": False, "port": 80}
config = defaults | {"port": 8080}    # {'debug': False, 'port': 8080}

字典的查找是 O(1)(哈希表),这是它与列表最大的性能差异,也是"用空间换时间"的经典设计。

实用技巧——计数与分组:

from collections import Counter, defaultdict

words = ["go", "py", "go", "sh", "go"]
Counter(words).most_common(2)          # [('go', 3), ('py', 1)]

groups = defaultdict(list)
for name, dept in [("a", "ops"), ("b", "dev"), ("c", "ops")]:
    groups[dept].append(name)          # {'ops': ['a', 'c'], 'dev': ['b']}

四、集合:无序不重复

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

a | b       # 并集 {1,2,3,4,5}
a & b       # 交集 {3}
a - b       # 差集 {1,2}
a ^ b       # 对称差 {1,2,4,5}

# 最常见用途: 去重
dup = [1, 3, 2, 3, 1]
unique = list(set(dup))        # [1, 2, 3](顺序不保证)

# 成员判断 O(1), 大列表判存在性时先转 set
valid = {"prod", "staging"}
if env in valid: ...

五、推导式:Pythonic 的灵魂

# 列表推导式
squares = [x * x for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]

# 带条件表达式
labels = ["偶" if x % 2 == 0 else "奇" for x in range(5)]

# 字典推导式
word_len = {w: len(w) for w in ["go", "python", "shell"]}
# {'go': 2, 'python': 6, 'shell': 5}

# 集合推导式
first_chars = {w[0] for w in ["apple", "avocado", "banana"]}

# 生成器表达式: 惰性求值, 省内存
total = sum(x * x for x in range(1_000_000))

六、怎么选?

需求 选择 原因
有序、会增删 list 通用序列
固定不变的配对/坐标 tuple 不可变、可哈希
按 key 快速查找 dict O(1) 查找
去重、交并差 set O(1) 成员判断
一次性大数据流 生成器 不占内存

实战小例子:日志状态统计

import re
from collections import Counter

stats = Counter()
with open("access.log") as f:
    for line in f:
        m = re.search(r'" (\d{3}) ', line)
        if m:
            stats[m.group(1)] += 1

for code, n in stats.most_common():
    print(f"{code}: {n}")

字典 + Counter + 推导式,几行代码顶半页 if-else。

小结

四大结构一句话:列表管顺序、元组管不变、字典管映射、集合管唯一。加上推导式,就是 Python 数据处理的全部地基。


本文是「Python」系列第 2 篇。