当前位置:首页>python>99% 的 Python 新手都分不清的两件事

99% 的 Python 新手都分不清的两件事

  • 2026-10-11 06:06:53
99% 的 Python 新手都分不清的两件事
刚学 Python 那会儿,我以为 ==  就是判断相等,is 也是判断相等,区别只是写法不同。

直到有一天写了这段代码:

a = [1, 2, 3]b = [1, 2, 3]print(a == b)  # Trueprint(a is b)  # False

当时我就懵了,明明内容一样,为什么 is 说不一样?

后来搞明白了,这俩压根不是一回事。


第一件事:== vs is

== 比较的是"值"
a = [1, 2, 3]b = [1, 2, 3]print(a == b)  # True —— 内容相同

== 调用的是对象的 __eq__ 方法,比较的是两个对象的内容是否相等。

is 比较的是"身份"
a = [1, 2, 3]b = [1, 2, 3]print(a is b)  # False —— 不是同一个对象

is 比较的是两个对象在内存中的地址(id()),也就是:是不是同一个东西。

a = [1, 2, 3]b = a  # b 指向同一个对象print(a == b)  # Trueprint(a is b)  # True —— 确实是同一个对象print(id(a) == id(b))  # True
那 is 什么时候返回 True?

对于不可变对象(int、str、tuple),Python 会做缓存复用:

# 小整数缓存(-5 到 256)a = 256b = 256print(a is b)  # True —— 同一个缓存对象a = 257b = 257print(a is b)  # False —— 超出缓存范围,两个不同对象
# 字符串驻留a = "hello"b = "hello"print(a is b)  # True —— 简单字符串会被驻留a = "hello world"b = "hello world"print(a is b)  # 不一定 —— 含空格的字符串不保证驻留
什么时候用 is?

判断 None 的时候,必须用 is:

# 正确if x is None:    print("x 是 None")# 不推荐if x == None:    print("x 是 None")

为什么?

因为 == None 会调用 __eq__,某些库重写了这个方法可能导致意外行为。is None 比较的是身份,不可能出错。

其他场景用 == 就够了。


第二件事:深拷贝 vs 浅拷贝

先看一个例子
original = [[1, 2], [3, 4]]copy = original.copy()  # 浅拷贝copy[0][0] = 999print(original)  # [[999, 2], [3, 4]] —— 原来也被改了!

明明用了 .copy(),为什么原来的列表也变了?

浅拷贝:只拷贝外壳
original = [[1, 2], [3, 4]]copy = original.copy()

浅拷贝做的事情:

copy → [引用A, 引用B]           ↓        ↓original → [引用A, 引用B]               ↓        ↓            [1, 2]   [3, 4]    ← 内层列表只有一份

外壳(外层列表)是新的,但里面装的元素(内层列表)还是同一个引用。

所以 copy[0][0] = 999 修改的是内层列表,原始和拷贝共享同一个内层列表,自然都变了。

深拷贝:完全独立的副本
import copyoriginal = [[1, 2], [3, 4]]deep = copy.deepcopy(original)deep[0][0] = 999print(original)  # [[1, 2], [3, 4]] —— 原来不受影响

深拷贝会递归地复制所有层级,内层列表也是全新的对象:

deep → [引用C, 引用D]            ↓        ↓         [1, 2]   [3, 4]     ← 新的内层列表original → [引用A, 引用B]               ↓        ↓            [1, 2]   [3, 4]  ← 原来的内层列表
常见的浅拷贝方式
lst = [1, 2, 3]copy1 = lst.copy()       # 方法一copy2 = lst[:]           # 方法二copy3 = list(lst)        # 方法三# 字典d = {"a": [1, 2]}copy4 = d.copy()         # 浅拷贝copy5 = dict(d)          # 浅拷贝# 列表推导式也是浅拷贝copy6 = [x for x in lst]
什么时候用深拷贝?

当数据结构是嵌套的(列表套列表、字典套列表等),而且你需要完全独立的副本时:

import copy# 场景:游戏存档game_state = {    "player": {"hp": 100, "inventory": ["sword", "shield"]},    "enemies": [{"type": "goblin", "hp": 50}]}# 浅拷贝:改存档会影响原始状态save = game_state.copy()save["player"]["hp"] = 0print(game_state["player"]["hp"])  # 0 —— 崩了# 深拷贝:完全独立save = copy.deepcopy(game_state)save["player"]["hp"] = 0print(game_state["player"]["hp"])  # 100 —— 没事

如果是简单的一维数据(纯数字列表、纯字符串列表),浅拷贝就够了。


对照表

场景用什么为什么
判断是否为 Noneis None比较身份,不可能出错
比较两个值是否相等==比较内容
判断是否为同一个对象is比较内存地址
复制一维列表/字典.copy() / 切片浅拷贝够用,性能好
复制嵌套结构copy.deepcopy()需要完全独立
函数传参防止被改copy.deepcopy()避免副作用

防坑清单

检查项怎么查
用 is 还是 ==?判断 None 用 is,其他用 ==
复制会不会互相影响?嵌套结构必须用 deepcopy
不确定对象是不是同一个?print(id(a), id(b)) 看地址

一句话总结:

== 比较值,is 比较身份;浅拷贝拷外壳,深拷贝全拷贝。搞混了,数据就互相污染。


Python 的"相等"和"同一个"是两回事,"拷贝"和"深拷贝"也是两回事。概念不清,bug 不停。

评论区聊聊:你被 is 和 == 坑过吗?还是被浅拷贝坑过?

下期预告:为什么你的 for 循环这么慢?——数据结构选错了,性能差 100 倍


我是鲁叶的Python,10年互联网古法程序员。
Python/ML/DL/大模型都折腾过,坑也踩了不少。
关注我,持续输出实用干货。

最新文章

随机文章