news 2026/9/1 3:02:02

Python 的 is 和 == 到底怎么选:小整数缓存、字符串驻留与 None 判断的坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 的 is 和 == 到底怎么选:小整数缓存、字符串驻留与 None 判断的坑

Python 的 is 和 == 到底怎么选:小整数缓存、字符串驻留与 None 判断的坑

有人写了个缓存命中判断,if user_id is 100000:,本地测试小 id 全对,上了生产大 id 全部命中失败,排查半天发现是is用错了。is==看着都是「判断相等」,但一个比的是「是不是同一个对象」,一个比的是「值相不相等」。混用平时不出事,一旦踩中 Python 的对象缓存机制,就会出现「本地对、线上错」这种最难查的 bug。这篇把两者的区别、以及那几个反直觉的缓存坑讲清楚。

先划清楚:is 比身份,== 比值

  • ==调用对象的__eq__方法,比较的是值是否相等
  • is比较的是两个变量是不是指向内存里同一个对象,等价于id(a) == id(b)
a=[1,2,3]b=[1,2,3]print(a==b)# True,两个列表值相等print(aisb)# False,是内存里两个不同的列表对象c=aprint(cisa)# True,c 和 a 指向同一个列表

这里ab值一样但不是同一个对象,所以==为真、is为假。这是最该建立的直觉:大多数时候你想判断的是「值相等」,那就该用==

坑一:小整数缓存,让 is 在小数字上「碰巧对」

Python 启动时会预先缓存 -5 到 256 之间的整数对象(小整数池),这个范围内的数字,无论你在哪写,拿到的都是同一个对象。于是:

a=100b=100print(aisb)# True —— 因为 100 在缓存范围内,是同一个对象x=100000y=100000print(xisy)# False —— 超出缓存范围,是两个不同对象print(x==y)# True —— 值当然相等

这就是开头那个 bug 的真相:user_id is 100000,当 id 小的时候可能碰巧命中缓存返回 True,id 一大就永远是 False。is判断整数相等是错的,哪怕它有时候「看起来对」。判断数值相等永远用==

顺带一提,-5~256这个范围是 CPython 的实现细节,别依赖具体数字,换个 Python 版本或解释器都可能变——这更说明了不该拿is比数字。

坑二:字符串驻留(intern),同样是「有时对有时错」

Python 对字符串也有类似优化,叫intern(驻留):像标识符那样的短字符串(只含字母数字下划线的字面量)会被驻留成同一个对象:

a="hello"b="hello"print(aisb)# True,被驻留了# 但拼接出来的、或含特殊字符的,通常不驻留c="hello world"d="hello world"print(cisd)# 可能 False(取决于实现)# 运行时拼出来的更不保证e="hel"+"lo"# 编译期常量折叠,可能 Truef="".join(["h","e","l","l","o"])# 运行期拼接print(eisf)# 大概率 False

结论一样:判断字符串内容相等,用==,永远别用is驻留是解释器背着你做的优化,你不该依赖它,也不该被它坑。

is 真正该用在哪:和单例比较,尤其是 None

is是不是就没用了?不是。is的正确用武之地是和「单例对象」比较——那些整个程序里只有一个实例的对象:NoneTrueFalse。其中最重要的是None:

deffind(items,target):result=lookup(items,target)# 可能返回 None,也可能返回 0、""、[]ifresultisNone:# 正确:明确判断「没找到」return"not found"returnresult

判断 None 必须用is None/is not None,不能用== None原因有两个:

  1. None是全局唯一单例,is判身份最准确、最快,不用调__eq__
  2. 更重要的是安全性:如果用== None,而对象自定义了__eq__,可能被改写出诡异行为:
classWeird:def__eq__(self,other):returnTrue# 恶意/疏忽:和任何东西都相等w=Weird()print(w==None)# True —— 被 __eq__ 骗了!print(wisNone)# False —— is 不会被 __eq__ 影响,如实反映身份

is绕过__eq__直接比身份,所以判断「是不是那个唯一的 None」时它既快又不会被糊弄。PEP 8 明确规定:和 None 比较要用is/is not

坑三:别用 is 判断 True/False,更别拿它当真值判断

x=1print(x==True)# True(1 == True,因为 True 本质是 1)print(xisTrue)# False(x 是整数 1,不是布尔单例 True)

判断一个值是否为真,直接if x:就好,别写if x is True:——它只在 x 恰好是布尔True那个对象时才成立,x = 1都会挂。

一张速查表

你想判断正确写法别用
两个值是否相等a == ba is b
是不是 Nonex is Nonex == None
是不是同一个对象a is ba == b
某个值是否为真if x:if x is True:

小结

  • ==(走__eq__),is身份(是不是同一个对象,等价于id()相等)。绝大多数「相等判断」需求都该用==
  • 小整数缓存(-5~256)和字符串驻留会让is在小数字/短字符串上「碰巧返回 True」,这是「本地对、线上错」类 bug 的经典来源——别拿is比数字和字符串。
  • is的正解是和单例比较,尤其is None/is not None:更快、且不会被自定义__eq__糊弄(PEP 8 强制要求)。
  • 判断真值用if x:,别用is True
  • 一句话记忆点:比值用 ==,认对象(尤其 None)用 is;拿 is 去比数字或字符串,迟早被缓存坑。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 3:00:26

CWRU轴承数据集深度解析:Python处理与故障诊断实战指南

简介:凯斯西储大学(CWRU)轴承数据集是机械故障诊断领域的经典基准资源,涵盖正常、内环故障、外环故障、滚珠故障等多种工况的振动信号,适用于滚动轴承故障识别与诊断研究,可满足故障诊断初学者、设备健康管理研究者及机器学习建模…

作者头像 李华
网站建设 2026/9/1 2:58:37

一级能效72%热效率燃气灶,嵌入式安装避坑指南

家里燃气灶退役,很多人第一眼就会被“一级能效嵌入式天然气灶具”“72%热效率”“双灶联动”“智能大火力”“节能猛火”这串词吸引。我的建议是:先别急着下单,先弄清楚这些词在你的厨房里到底意味着什么。嵌入式天然气灶具不是看谁文案写得猛…

作者头像 李华
网站建设 2026/9/1 2:58:09

智慧社区老人安全监护系统:从跌倒检测到告警闭环的设计实践

一个独居老人如果在家摔倒,最怕的不是摔倒本身,而是摔完之后没有人知道。许多智慧社区项目启动时,第一件想做的事就是给老人家里装摄像头和报警器。可实际项目里真正能稳定用起来的不多:要么告警全量堆在群里没人看,要…

作者头像 李华
网站建设 2026/9/1 2:57:13

基于LSTM与Encoder-Decoder的UCF101视频动作识别实战

简介:结合LSTM的encoder-decoder模型在UCF101动作识别任务中的完整实践包,面向视频分类初学者与进阶研究者,旨在解决时序动作建模、长程依赖捕捉与特征融合问题。压缩包为7z格式,共90个文件,整体8.93MB,包含…

作者头像 李华
网站建设 2026/9/1 2:56:14

RAG的9种架构,你用的是哪一种?

最近总有人问我,RAG 到底怎么做。 我说你具体想做什么。 十有八九,对方描述的是同一个东西:把文档切块、做向量化、存进向量数据库,用户提问的时候检索出最相关的几段,拼进 prompt 丢给大模型。 我说,这…

作者头像 李华
网站建设 2026/9/1 2:53:02

LLM与经典机器学习协同实战:从特征工程到文本分类

最近在做一个文本风控项目时,团队里争论了一个很有意思的问题:既然大语言模型(LLM)已经能读懂长文本、能写摘要、能做情感分析,那我们为什么还要保留 XGBoost、逻辑回归这些经典机器学习模型?干脆全换成 LL…

作者头像 李华