is比较对象身份(内存地址),==比较值相等;唯一推荐用is的场景是与none等单例比较,小整数和字符串的is行为属cpython实现细节,不可依赖。

is 判断的是对象身份,不是值是否相等
is 比较的是两个变量是否指向内存中**同一个对象**,即 id(a) == id(b)。它不关心内容,只看引用地址。比如 None、小整数(-5 到 256)、短字符串等会被缓存复用,这时候 is 可能意外返回 True,但这只是实现细节,不能依赖。
常见错误现象:
- if x is True: —— 应该用 if x: 或 if x is True: 仅当明确需区分 True 和真值时才用,但多数情况是错的
- [] is [] 返回 False,因为每次 [] 都新建对象
- a = [1]; b = a; a is b 返回 True,因为没创建新对象
== 默认调用 __eq__,可被重载,用于逻辑相等判断
== 是“相等性”操作符,底层调用对象的 __eq__ 方法。内置类型如 int、str、list 已实现合理比较逻辑;自定义类若不重写 __eq__,则退化为 is(即比较身份)。
使用场景和注意事项:
- [1, 2] == [1, 2] 返回 True,而 [1, 2] is [1, 2] 是 False
- float('nan') == float('nan') 返回 False,这是 IEEE 754 规定,但 math.isnan() 才是正确判断方式
- 自定义类中若忽略 __eq__,两个内容相同但不同实例的比较结果会是 False,容易引发 bug
什么时候必须用 is,什么时候绝不能用 is
唯一安全、推荐使用 is 的场景是与单例对象比较,尤其是 None。
- ✅ 正确:if x is None:、if y is not None:
- ❌ 危险:if x is True:(应改用 if x is True: 仅在需要排除 1、[1] 等真值时;更常见的是直接 if x:)
- ❌ 错误:if len(lst) is 0:(len() 返回 int,但这里语义是“空”,应写 if not lst:)
- ⚠️ 陷阱:if a is b and a == b: 不等于“a 和 b 完全等价”,因为 is 成立时 == 必然成立(除非 __eq__ 被恶意重写为总是返回 False)
小整数和字符串的 is 行为是 CPython 实现细节,不可移植
CPython 对 -5 到 256 的整数做了对象池优化,所以 256 is 256 是 True,但 257 is 257 在某些上下文(如交互式环境 vs 脚本)中可能为 False;字符串字面量也可能被驻留(interned),但带变量拼接的就不再保证。
示例:a = 257; b = 257; a is b → 在脚本里常为 False,但在交互式解释器同一行输入可能是 Trues1 = "hello"; s2 = "hello"; s1 is s2 → 通常 Trues3 = "he" + "llo"; s4 = "hello"; s3 is s4 → 通常 True(编译期优化)s5 = "he" + llo_var; s6 = "hello"; s5 is s6 → 几乎总是 False
这类行为在 PyPy、Jython 或未来 CPython 版本中都可能变化,拿 is 做值比较就是埋雷。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











