Python列表与字典常用操作代码:增删改查及遍历

山间有风
山间有风
发布时间:2026-11-05 | 10人浏览过
原创

系统详解Python列表(List)与字典(Dictionary)的核心增删改查方法、遍历技巧、底层内存与哈希寻址机制、复杂度对比及常见工程避坑实践。

在 Python 开发中,列表(list)与字典(dict)是最常用的两种复合数据结构。列表是基于连续内存地址的动态有序序列,适合依赖索引顺序和支持重复元素的数据集;字典则是基于散列表(Hash Table)的键值对容器,擅长通过唯一标识进行高速查找。掌握两者的增、删、改、查与遍历代码及其底层时空复杂度差异,是编写健壮、高效 Python 代码的核心基础。
Python列表与字典常用操作代码:增删改查及遍历
图 1:Python 列表(有序序列)与字典(哈希映射)结构与特性概览

一、列表(List)的增删改查基础与代码实践

Python 中的列表属于变长数组(Dynamic Array),内部存储的是连续的指向具体 Python 对象的指针。访问特定索引元素的时间复杂度为常数级 O(1),但在中间插入或删除元素会引起后续指针的整体搬移。

1. 增加元素:append、insert、extend 与拼接

列表提供了多种追加或插入数据的方法,其适用条件与执行效率各有侧重:

  • append(x):将元素作为一个整体追加至列表末端。时间复杂度为均摊 O(1),是日常最推荐的单元素添加方式。
  • insert(index, x):在指定索引位置插入元素。插入位置后续的所有元素都会向后移动一位,时间复杂度为 O(n)。
  • extend(iterable):接收一个可迭代对象,逐个解包并追加到列表末尾,原地修改原列表。
  • + 运算符:新建并返回一个合并后的全新列表,不会改变原列表,但需要为新列表分配全新内存。
# 列表新增操作示例
scores = [85, 92]

# 1. 末尾追加单元素
scores.append(88)

# 2. 指定位置插入(在索引 1 处插入 99)
scores.insert(1, 99)

# 3. 批量追加可迭代对象
scores.extend([76, 84])

# 4. 加号拼接(生成新列表)
extra_scores = scores + [95, 100]

print("原地操作后 scores:", scores)
print("拼接生成的新列表 extra_scores:", extra_scores)
原地操作后 scores: [85, 99, 92, 88, 76, 84] 拼接生成的新列表 extra_scores: [85, 99, 92, 88, 76, 84, 95, 100]
Python列表与字典常用操作代码:增删改查及遍历
图 2:列表连续内存布局下的尾部操作 O(1) 与任意位置插入/删除 O(n) 位移机制

2. 删除元素:pop、remove、del 与 clear

根据删除依据(依据索引、依据值、或者彻底清空),选择对应的操作命令:

  • pop([index]):移除并返回指定索引处的元素。若省略参数,默认弹出末尾元素 pop(),耗时 O(1);若指定非末尾索引(如 pop(0)),耗时 O(n)。索引越界时抛出 IndexError。
  • remove(value):按值查找并移除首次出现的匹配项。需要遍历比对元素,耗时 O(n)。若目标值不存在,抛出 ValueError。
  • del lst[index] / del lst[start:end]:语句级别删除,支持单索引或切片批量清除,直接回收对应槽位。
  • clear():移除列表中所有元素,保留原列表对象引用,长度归零。
tasks = ["email", "review", "meeting", "review", "deploy"]

# 1. 弹出末尾元素并获取返回值
last_task = tasks.pop()

# 2. 弹出指定索引元素
first_task = tasks.pop(0)

# 3. 移除指定值的第一个匹配项(删除第一个 "review")
tasks.remove("review")

# 4. 使用 del 删除切片或指定位置
del tasks[0]

# 5. 清空列表
backup = ["temp"]
backup.clear()

print("当前 tasks:", tasks)
print("弹出的任务:", first_task, last_task)
print("清空后的 backup:", backup)
当前 tasks: ['review'] 弹出的任务: email deploy 清空后的 backup: []
安全提醒:remove 前建议使用 in 预检或捕获异常
直接调用 lst.remove(x) 在元素不存在时必定抛出 ValueError: list.remove(x): x not in list。在不确定元素是否存在时,应通过 if x in lst: lst.remove(x) 或使用 try...except ValueError: 包裹执行。

3. 修改与查询元素

由于列表具备整齐的数字索引,直接索引取值和赋值均为 O(1) 极速操作。此外还支持切片批量替换与元素查找:

nums = [10, 20, 30, 40, 50]

# 1. 单元素索引修改
nums[1] = 25

# 2. 切片批量修改(将索引 2 至 4 的切片替换为新序列)
nums[2:4] = [35, 45, 48]

# 3. 查询元素:通过正向或反向索引
val = nums[-1]

# 4. 判断成员是否存在(时间复杂度 O(n))
exists = 35 in nums

# 5. 查找元素首个出现索引与出现频次
idx = nums.index(35)
cnt = nums.count(35)

print("修改后 nums:", nums)
print(f"末尾值: {val}, 存在性: {exists}, 35首次出现的索引: {idx}, 出现频次: {cnt}")
修改后 nums: [10, 25, 35, 45, 48, 50] 末尾值: 50, 存在性: True, 35首次出现的索引: 2, 出现频次: 1

二、字典(Dictionary)的增删改查机制与代码实践

Python 字典是基于哈希表实现的键值关联映射。自 Python 3.7 起,标准字典官方保证保留键值对的插入顺序。向字典中检索、插入或删除任意键值的平均时间复杂度均为 O(1)。

Python列表与字典常用操作代码:增删改查及遍历
图 3:字典哈希寻址阶段与安全存取决策路径

1. 增加与修改键值对:方括号、update 与 setdefault

在字典中,增加一个新键与修改已有键在语法上是完全统一的:

  • d[key] = value:当 key 不存在时新增键值对;当 key 已存在时直接覆盖对应的值。
  • update(other_dict_or_iterable):批量合并另一个字典或键值对迭代器。相同键会被新值覆盖,缺失键会被新增。
  • setdefault(key, default):若 key 存在,则直接返回其当前值;若不存在,则在原字典中插入 key: default 并返回该默认值。非常适合在分组或聚合计数时初始化容器。
# 字典增改代码示例
user_profile = {"id": 1001, "name": "Alice"}

# 1. 单键赋值(不存在则新增,存在则更新)
user_profile["role"] = "Engineer"
user_profile["name"] = "Alice Cooper"

# 2. 批量合并与更新
user_profile.update({"dept": "R&D", "status": "Active"})

# 3. setdefault 用于安全初始化复杂嵌套类型
user_tags = {}
user_tags.setdefault(1001, []).append("Python")
user_tags.setdefault(1001, []).append("Backend")

print("更新后的 profile:", user_profile)
print("分组标签字典:", user_tags)
更新后的 profile: {'id': 1001, 'name': 'Alice Cooper', 'role': 'Engineer', 'dept': 'R&D', 'status': 'Active'} 分组标签字典: {1001: ['Python', 'Backend']}

2. 查询与读取:方括号 vs get 方法

访问字典数据时,需根据键是否确定存在来选择策略:

  • d[key]:直接访问。若键不存在,立即抛出 KeyError。只在业务逻辑百分之百确认该键必须存在时使用。
  • d.get(key, default=None):安全取值。若键存在返回对应值;若不存在返回 default(默认为 None),不会抛出异常。
  • key in d:检查指定键是否位于字典中,平均耗时仅 O(1)。
config = {"timeout": 30, "retries": 3}

# 1. 确定存在的键直接方括号访问
timeout = config["timeout"]

# 2. 不确定存在的键使用 get 并赋予默认备选值
host = config.get("host", "127.0.0.1")
port = config.get("port", 8080)

# 3. 成员检查
has_retries = "retries" in config
has_ssl = "ssl" in config

print(f"超时: {timeout}, 主机: {host}, 端口: {port}")
print(f"包含retries: {has_retries}, 包含ssl: {has_ssl}")
超时: 30, 主机: 127.0.0.1, 端口: 8080 包含retries: True, 包含ssl: False

3. 删除键值:pop、popitem、del 与 clear

字典提供了多种针对键的删除策略:

  • pop(key[, default]):移除指定键并返回对应的值。若键不存在且提供了 default 参数,则返回 default;若未提供则抛出 KeyError。
  • popitem():按照后进先出(LIFO)顺序移除并返回最后一个键值对元组 (key, value)。字典为空时调用抛出 KeyError。
  • del d[key]:删除指定键值。若键不存在抛出 KeyError。
  • clear():清空字典内所有键值对。
session = {"token": "xyz890", "ip": "192.168.1.10", "login_time": 1700000000}

# 1. pop 安全删除并取值(设置默认值防崩)
token_val = session.pop("token", None)
missing_val = session.pop("device_id", "Unknown")

# 2. popitem 移除最新加入的项
last_pair = session.popitem()

# 3. del 语句删除
if "ip" in session:
    del session["ip"]

print("剩余 session:", session)
print("获取到的 token:", token_val, "缺失键安全返回值:", missing_val)
print("弹出的最后键值对:", last_pair)
剩余 session: {} 获取到的 token: xyz890 缺失键安全返回值: Unknown 弹出的最后键值对: ('login_time', 1700000000)

三、列表与字典的遍历技巧与实战模式

遍历是处理集合数据的必经步骤。针对不同场景,选用正确的遍历语法能显著提高代码的可读性与运行效率。

1. 列表的高效遍历方式

  • 直接迭代元素:for item in lst: 最自然的迭代方式,无需维护索引变量。
  • 带索引迭代(enumerate):for idx, item in enumerate(lst, start=0): 同时获得当前索引与对应元素,避免使用低效且冗长的 range(len(lst))。
  • 并行迭代(zip):for a, b in zip(list_a, list_b): 同时配对遍历多个等长或不等长列表。
  • 列表推导式(List Comprehension):[expr for item in lst if condition] 简洁、高效地过滤或映射并生成新列表。
names = ["Alice", "Bob", "Charlie"]
roles = ["Admin", "Dev", "QA"]

# 1. 同时需要索引和值:enumerate
print("--- enumerate 遍历 ---")
for idx, name in enumerate(names, start=1):
    print(f"编号 {idx}: {name}")

# 2. 多列表并行聚合:zip
print("--- zip 遍历 ---")
for name, role in zip(names, roles):
    print(f"成员 {name} -> 角色 {role}")

# 3. 列表推导式提取大写
upper_names = [n.upper() for n in names if len(n) > 3]
print("长度大于3的大写名称:", upper_names)
--- enumerate 遍历 --- 编号 1: Alice 编号 2: Bob 编号 3: Charlie --- zip 遍历 --- 成员 Alice -> 角色 Admin 成员 Bob -> 角色 Dev 成员 Charlie -> 角色 QA 长度大于3的大写名称: ['ALICE', 'CHARLIE']

2. 字典的高效遍历方式

字典提供了三种动态视图对象:keys()、values()、items():

  • for key in d: 默认直接遍历所有键。
  • for val in d.values(): 仅遍历所有值,当不需要键时省去查询开销。
  • for key, val in d.items(): 同时解包遍历键和值,工程中最常用的模式。
  • 字典推导式:{k: v for k, v in d.items() if condition} 快速完成字典的键值翻转、条件过滤或数据转换。
product_prices = {"Apple": 6.5, "Banana": 3.2, "Cherry": 18.0}

# 1. 遍历键值对并解包
print("--- items 遍历 ---")
for fruit, price in product_prices.items():
    print(f"商品: {fruit:8s} 单价: ¥{price:.2f}")

# 2. 仅遍历值计算总和
total_price = sum(product_prices.values())
print(f"商品价格总和: ¥{total_price:.2f}")

# 3. 字典推导式:打折并筛选高价商品
discounted = {f: round(p * 0.9, 2) for f, p in product_prices.items() if p > 5.0}
print("九折高价商品:", discounted)
--- items 遍历 --- 商品: Apple 单价: ¥6.50 商品: Banana 单价: ¥3.20 商品: Cherry 单价: ¥18.00 商品价格总和: ¥27.70 九折高价商品: {'Apple': 5.85, 'Cherry': 16.2}
Python列表与字典常用操作代码:增删改查及遍历
图 4:在遍历过程中直接修改容器的典型陷阱及三种工程安全规避方案

四、关键转折与高频避坑实践

1. 为什么“边遍历边删除”会导致严重逻辑漏洞?

这是初学者最容易踩中的暗坑:

  • 列表跳项问题:在正向 for x in lst: 循环中,Python 内部通过累加的整数游标追踪当前读取位置。一旦调用 lst.remove(x) 或 del lst[i],后面的所有元素会被立即向前搬移填补空缺,导致紧邻被删元素的下一个元素跳过了当前游标的检查。
  • 字典运行时崩溃:在字典遍历过程中如果直接添加或删除键,Python 解释器在检测到哈希表结构变更后会立即抛出 RuntimeError: dictionary changed size during iteration。

工程推荐解决策略:

  1. 优先使用列表/字典推导式重新生成过滤后的新对象,表达清晰且执行速度最快。
  2. 若必须在原对象上进行原地清理,可使用切片浅拷贝或键列表快照:for x in lst[:]: 或 for k in list(d.keys()):。
  3. 对于极长列表且内存敏感时,采用逆序循环索引:for i in range(len(lst)-1, -1, -1): del lst[i],从后向前删除不会影响前部待处理元素的索引相对位置。

2. 函数默认参数切勿使用可变对象([] 或 {})

在定义函数时,默认参数在函数定义被解释执行时仅创建一次。如果将默认参数写为 def add_item(val, container=[]),后续多次调用该函数且不传递实参时,所有调用都将共享这同一个列表对象,造成隐蔽的数据污染。

# 错误示例:共享可变对象
def append_wrong(item, bag=[]):
    bag.append(item)
    return bag

# 正确示例:使用 None 并在函数体内动态初始化
def append_correct(item, bag=None):
    if bag is None:
        bag = []
    bag.append(item)
    return bag

print("错误调用第1次:", append_wrong(1))
print("错误调用第2次:", append_wrong(2)) # 输出 [1, 2],状态发生意外残留!

print("正确调用第1次:", append_correct(10))
print("正确调用第2次:", append_correct(20)) # 输出 [20],各次调用相互独立
错误调用第1次: [1] 错误调用第2次: [1, 2] 正确调用第1次: [10] 正确调用第2次: [20]

五、常用操作时间复杂度与选型全景矩阵

合理选择数据结构的前提是理解底层计算成本。下表汇总了列表与字典常用操作的时间复杂度:

数据结构 操作类型 典型方法 / 语法 时间复杂度 潜在异常与安全建议
列表 (List) 追加 / 尾删 append() / pop() O(1) 均摊 性能最优;空列表 pop 抛出 IndexError
任意插入 / 删除 insert(i, x) / pop(i) / remove() O(n) 引起元素指针整体移位;remove 缺失抛 ValueError
按索引查 / 改 lst[i] / lst[i] = v O(1) 索引越界抛 IndexError,需验证 0 <= i < len(lst)
成员包含性检查 x in lst O(n) 线性扫描比对;数据量大且需频繁查重时应转用 set/dict
字典 (Dict) 增 / 改键值 d[k] = v / setdefault() O(1) 平均 Key 必须为可哈希对象(如 str、int、tuple)
安全删除 pop(k, default) O(1) 平均 必须提供 default 兜底,防止抛 KeyError
查键值 d.get(k, default) O(1) 平均 键缺失无异常,返回默认值;比 k in d 更具可读性
键存在性检查 k in d O(1) 平均 基于哈希算法快速定址,效率显著高于列表遍历
Python列表与字典常用操作代码:增删改查及遍历
图 5:Python 列表与字典常用操作全景速查矩阵与时间复杂度图解

六、总结与工程选型启示

在 Python 日常开发中,列表与字典各司其职,遵循清晰的权衡边界:

  • 当处理具有自然先后顺序、允许重复项、主要在尾部增删的数据集合时,列表(list)是最轻量、直观的选择。如果你的应用场景需要频繁在头部插入或移除元素,则应选用标准库中的 collections.deque。
  • 当处理需要按唯一标识高速存取、关联属性映射、频繁进行存在性查重的数据集时,字典(dict)是绝对首选。其平均 O(1) 的查找与插入开销能让千万级数据在毫秒级内完成检索。
  • 在编写涉及动态集合修改的业务逻辑时,牢记推导式重构优先、快照迭代保底的准则,彻底避免“边循环遍历边直接增删”造成的逻辑死角与运行时异常。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表