page contents

面试官:Python 中的 is 和 == 有什么区别?

前几天在面试一个 Python 后端岗的时候,那个面试官啊,突然抛了个看似简单的问题:“你能说下 is 和 == 有什么区别吗?”我当时笑了一下,说这玩意儿每年都有人栽坑。你别看这俩符号就差一个单词,真要分不清,代码就得出妖。那天晚上回来我还跟小王唠叨了半天,越聊越觉得这题其实挺有意思的。

attachments-2025-10-Y5pMr8tp68fc279b3d4e3.png前几天在面试一个 Python 后端岗的时候,那个面试官啊,突然抛了个看似简单的问题:“你能说下 is 和 == 有什么区别吗?”我当时笑了一下,说这玩意儿每年都有人栽坑。你别看这俩符号就差一个单词,真要分不清,代码就得出妖。那天晚上回来我还跟小王唠叨了半天,越聊越觉得这题其实挺有意思的。

先说结论哈,别卖关子。is 比的是 对象的身份(id),也就是两个变量是不是指向同一个内存地址;== 比的是 对象的值(value),也就是两个东西看起来是否相等。一个是“你俩是不是同一个人”,一个是“你俩长得像不像”。有时候两者会一起成立,有时候就不。

举个最典型的例子,我当时面试的时候直接在白板上写了:

a = [123]
b = [123]
print(a == b)  # True
print(a is b)  # False

这段一跑,面试官点头说不错。a 和 b 是两个不同的列表对象,只是内容一样,所以 == 返回 True,但它们的内存地址不一样,is 就是 False。要是你搞混这俩,你后面写判断逻辑的时候会被坑惨,特别是 mutable(可变类型)那种。

然后我又接着举了个字符串的例子,哎,这个才是最容易出错的:

x = "hello"
y = "hello"
print(x == y)  # True
print(x is y)  # True(有时候)

为啥我说“有时候”呢?因为 Python 会对一些小字符串和小整数做缓存(也叫驻留),比如字符串常量、短整数,解释器会复用内存。所以你写两个一样的 "hello",有可能 is 也成立。但这不是规律保证的,不能依赖这个行为写逻辑。你要是去拼接、读取文件得到的新字符串,那 is 多半就挂了。比如:

x = "hello world"
y = "hello " + "world"
print(x is y)  # 在某些解释器下 True,但不保证

还有个更阴的例子,整数缓存:

a = 256
b = 256
print(a is b)  # True

c = 257
d = 257
print(c is d)  # False

这就很魔幻对吧?因为 Python 默认会缓存 -5 到 256 之间的整数,这个区间内的对象都复用内存地址。所以 a 和 b 指向的是同一个整数对象。但超过 256,就各分配新空间了,is 一下就断了。面试官一般就爱抓这种边界,看你到底懂不懂底层内存分配那套。

其实我挺喜欢用人比喻去解释。你想象一下啊,== 是说“你俩身份证上生日一样”,而 is 是说“你俩是不是一个人”。有时候你俩长得像(值一样),但身份证号肯定不一样(对象不同)。只有在某些特殊情况下,比如 Python 优化了,把这俩人的身份证号都搞成一样的,那 is 也就意外成立了。

后来小王问我,既然有 ==,那 is 存在意义在哪?我说这玩意儿是区分“同一个对象”跟“等值对象”的关键。比如单例模式的时候,你就得用 is。最常见的例子就是判断一个变量是不是 None。

x = None
if x is None:
    print("空的")

千万别写成 x == None,虽然大多数时候结果一样,但后者是走 __eq__ 运算符,可能会被重载导致结果乱套。官方文档都明确建议——判断 None 一定要用 is,这是个习惯问题。写代码写久了你会发现,这种细节是区分“刚学过”和“真懂语言”的分水岭。

我记得那会儿公司里有人写了个自定义类,还重载了 __eq__,结果在判断是否为 None 的时候返回了 True,全组 debug 到凌晨两点。后来一查发现是人家把比较逻辑写死了……那一瞬间大家都明白为什么官方要强调 is None 了。

再说一个挺有意思的点,就是 is 和 == 在对象模型层面的实现。is 实际上就是比较对象的 id 值,也就是 id(a) == id(b)。你去 print(id(a)),会看到一个整数,代表内存地址。== 则是调用对象的 __eq__ 方法。不同类型的 __eq__ 实现可能不一样,比如 list 的比较是逐元素比较,str 的比较是按字符序列,dict 是键值对的集合比较。这也是为啥 == 可以灵活用,而 is 只是单纯的身份判断。

有时候在性能上,两者也有差别。is 就是一个地址对比,非常快;== 要去调 __eq__,还可能涉及深层遍历。你像两个超长列表做 == 比较,得 O(n);而 is 永远是 O(1)。所以在某些对性能极度敏感的判断逻辑里,能用 is 就别滥用 ==。当然,大部分业务场景下这点差距根本不重要,除非你在写底层框架。

我还记得有个老同事写配置解析器的时候,用了一堆 if val == Trueif val == False 这种,结果布尔判断都出 bug。因为 Python 的 bool 是 int 的子类,True == 1,False == 0,这一连串比较全乱套。最后我给他改成 if val is True: 直接定位身份问题,一下子稳了。后来我们组开玩笑说:谁再用 == True,罚喝咖啡一杯。

对了,这里也顺便说一下,布尔值其实就是整数对象的“皮肤”,True is 1 是 False,但 True == 1 是 True。是不是感觉脑子有点打结?这就说明 == 走的是值比较(1 == 1),而 is 比的对象身份,根本不是一个对象。Python 就是这么灵活,但也容易坑新手。

讲到这儿差不多你就能总结出一条经验法则了:如果你关心两个变量是不是同一个对象,用 is;如果你关心它们的内容是不是一样,用 ==。 除此之外,还有一条我自己写代码时养成的“小动作”——我从来不在复杂类型上用 is 除了 None。别问,问就是防炸。因为除了 None、True、False 这些单例对象,其他的 is 结果都不保证。

我还记得有一次项目上线前的凌晨,我查日志发现一堆奇怪的条件没触发,最后发现同事写了个判断 if result is []:。这啥意思啊?每次那 [] 都是新创建的对象,怎么可能和别的列表地址一样?当然永远是 False。那一夜我喝了仨红牛把那几百行 if 换成 == 才搞定。那种痛苦,真的一辈子都忘不了。

后来我就跟组里的新人说,判断空列表、空字符串这些都老老实实用 == [] 或 not list,别碰 isis 是刀,切得准的时候很利,但用错地方能直接切自己。

到这儿其实面试官要的是你理解背后的“内存引用模型”和“值语义区别”,不是死记硬背定义。很多人答“is 比地址,== 比值”,然后完了。其实他要看的是你知不知道 Python 在背后偷偷帮你缓存对象、你能不能举出实际出 bug 的例子、能不能说出 None 判断的最佳实践。那才叫真懂。

我那天答完之后,面试官笑了笑,说你这解释挺生活化的。我说那当然,写 Python 写久了,这种坑踩一遍都能讲成故事。 所以最后总结一句——is 是“同一个对象”,== 是“值相等”,用的时候多想想你到底要比什么。别指望 Python 帮你聪明判断,有时候它只是恰好帮了你一回,下次就坑你了。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2025-10-25 09:28
  • 阅读 ( 22 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1479 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2228 文章
  3. Pack 1479 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章