一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Python切片赋值与普通赋值对比:你确定修改了原列表吗

时间:2026-05-22 08:50:01 编辑:袖梨 来源:一聚教程网

Python中切片赋值与普通赋值的区别,决定了你是否真正修改了原始对象。理解这一机制能避免许多编程陷阱。

一句话结论

a = new_list      # 换指针:a 指向新对象,原对象不变
a[:] = new_list   # 换内容:原对象被就地修改,所有引用者同步看到变化

1. 问题场景

当函数内部尝试修改传入的列表时,普通赋值可能达不到预期效果:

Python 切片赋值 vs 普通赋值:你真的改了那个 list 吗?

def compress(messages):
    summary = summarize(messages)
    messages = [summary]  # ← 这行有效吗?history = [msg1, msg2, msg3, ...]
compress(history)
print(history)  # 还是 [msg1, msg2, msg3, ...] !没变!

这是由于Python采用引用传递参数,而普通赋值仅改变局部变量的指向。


2. 内存模型图解

普通赋值 messages = new_list

调用前:
  history ──────┐
                ▼
  messages ───► [msg1, msg2, msg3]    ← 同一个对象赋值后:
  history ──────► [msg1, msg2, msg3]  ← 原对象,没人动它
  messages ────► [summary]            ← 新对象,局部变量换了指向

函数执行完毕时,局部变量messages被销毁,新对象被回收,而history保持不变。

切片赋值 messages[:] = new_list

调用前:
  history ──────┐
                ▼
  messages ───► [msg1, msg2, msg3]    ← 同一个对象赋值后:
  history ──────┐
                ▼
  messages ───► [summary]             ← 同一个对象,内容被替换了!

切片赋值操作直接修改原对象内容,保持对象id不变。


3. 验证:id 不变 vs id 变了

a = [1, 2, 3]
print(id(a))       # 4398046208# 普通赋值
a = [4, 5, 6]
print(id(a))       # 4398100032  ← id 变了!新对象# 切片赋值
a = [1, 2, 3]
print(id(a))       # 4398046208
a[:] = [4, 5, 6]
print(id(a))       # 4398046208  ← id 没变!同一个对象

4. 切片赋值的几种形式

语法含义等价操作
a[:] = x替换全部内容a.clear(); a.extend(x)
a[1:3] = x替换索引 1、2 的元素删掉旧的,插入新的
a[::2] = x替换偶数位置要求 len(x) 匹配
a[:0] = x在开头插入a = x + a 的就地版
a[len(a):] = x在末尾追加a.extend(x)
a = [0, 1, 2, 3, 4]
a[1:3] = [10, 20, 30]     # 可以长度不等!
print(a)                  # [0, 10, 20, 30, 3, 4]

5. 常见陷阱

陷阱 1:tuple 没有切片赋值

t = (1, 2, 3)
t[:] = (4, 5, 6)  # TypeError: 'tuple' object does not support item assignment

元组不可变,只能使用重新赋值的方式。

陷阱 2:dict 没有切片

d = {"a": 1}
d[:] = {"b": 2