Python 里 is 和 == 到底差在哪?拆开小整数池、字符串驻留与 0ns 身份比较

简介: is 比 == 快不是 Python 偷懒,而是它只比对象身份(指针),0ns 级别;== 要走 __eq__ 还可能触发哈希。但小整数池和字符串驻留会让 is 在「本不该相等」时也返回 True,这是 80% 初学者踩的坑。

很多人学 Python 第一个踩的坑就是 is 和 ==。一句话先说清:is 比较「是不是同一个对象」(身份),== 比较「值等不等」(内容)。下面用 CPython 3.13.14 实机跑出来的几组数据,把那些反直觉的地方拆开看。

一、小整数池:只缓存 -5 到 256

a, b = 256, 256
a is b          # True
a, b = int('257'), int('257')
a is b          # False(运行时现造的,不在池里)

为什么 256 是同一个、257 却不是?CPython 启动时把 -5 到 256 的整数对象预先建好放进池子复用,任何地方用到 256 都指向同一个对象。int('257') 是运行期现造的,自然各造各的。

注意一个干扰项:在同一个代码块里写两个 257(比如 a=257; b=257),a is b 也可能是 True——这不是小整数池,而是常量折叠(编译器把同一个常量合并进 co_consts 的一项)。一旦跨语句、跨函数用 int('257') 构造,真相就露出来了。

二、字符串驻留(intern):字面量默认复用

s1, s2 = 'hello', 'hello'
s1 is s2          # True(字面量被 intern)
s1, s2 = 'a'*20, 'a'*20
s1 is s2          # True(全同字符的重复串也会复用)
s1, s2 = 'a'*21, 'a'*21
s1 is s2          # True(实测 3.13 同样复用)

'hello' 这种合法标识符形式的字符串,CPython 默认驻留;而 'a'*20 这种运行期构造的串,3.13 实测也会复用(当结果全由同一字符组成时)。想强制驻留,调 sys.intern()。

三、可变对象:各是各的

l1, l2 = [], []
l1 is l2          # False
l1 == l2          # True(空列表内容相等)
l3 = l1
l1 is l3          # True(只是同一个对象的另一个名字)

列表、字典、集合这些可变的,永远不会自动共享,所以 is 必为 False,但 == 看内容。

四、性能:is 几乎零成本

拿一个 10 万字符的字符串实测:

a = 'x'*100000; b = 'x'*100000   # a、b 是两个不同对象,内容相同
a is b    # 只比指针,近乎 0ns
a == b    # 要判值,慢一个量级

is 就是比两个指针相不相等,CPU 一条指令的事;== 得进到对象的 __eq__,大对象要逐段比对。方向很确定:is 比 == 便宜得多。

五、实战里怎么选

  • 永远用 x is None,别用 x == None。None 是单例,身份比较又快又不会被重载坑。
  • 判断枚举、单例、哨兵值(sentinel = object()),用 is。
  • 比较数值、字符串内容、容器内容,用 ==。
  • 最经典的 bug:if x == None 在 x 重载了 __eq__ 时可能误判,而 is None 永远不会。

一句话记牢:比「是不是同一个」用 is,比「长得像不像」用 ==。

相关文章
|
1天前
|
缓存 Java Python
Python 的 int 为什么不会溢出?拆开 PyLongObject 和它背后那串变长数组
很多人背过“字典查询是 O(1)”,但为什么是常数?CPython 3.13 实测 dict.get 在 100→10 万规模恒为 0.1 微秒,而 list.index 线性涨到 609 微秒(慢 4743 倍)。本文拆开开放寻址哈希表、扰动函数与 2/3 扩容阈值把 O(1) 钉死,也讲清“创建是 O(n)”这个常被混的点。
|
12天前
|
存储 缓存 编译器
Python 的整数为什么永远不会溢出?拆开大整数对象,看 30 位一节的存储与运算代价
Python 整数不会溢出,靠的是把数字拆成 30 位小节用对象数组存:每个整数至少 28 字节,每多 30 位加 4 字节;加法近似线性、乘法超线性——30 万位乘法是 30 位的 29 万倍;str 转换默认 4300 位护栏,to_bytes 比 str 快约 300 倍。用 9 组实验算清「无限精度」的账单。
|
13天前
|
Java 索引 Python
Python 字典为什么这么快?一次查找背后的哈希表、扰动函数和开放寻址
Python 字典查找平均 O(1):算一次哈希直接跳到桶位,实测 1 万 key 取值 4.6ms,同规模列表成员判断要 55 秒,差 12000 倍;但哈希全碰撞时慢 2111 倍——用 4 组实验讲透开放寻址、扰动函数和空间换时间。
|
21天前
|
Python
Python 迭代器和生成器到底啥区别?3 个例子讲透,别再背概念了
迭代器和生成器不是并列关系——生成器是迭代器的一种“偷懒写法”。3 个例子讲透:迭代器是“会挨个吐值的对象”,生成器是用 yield 现写现用的那种,最大区别是它懒,要一个才生一个。
|
22天前
|
Python
Python 装饰器到底是个啥?从 @ 符号到手写一个,5 个例子讲透
装饰器(decorator)本质是一个「接收函数、返回函数」的高阶函数,@log 写在 def foo() 上等价于 foo = log(foo)。本文从最朴素的包装工厂讲起,用 5 个例子把 @ 语法、functools.wraps、带参数装饰器、类装饰器一次讲透。
|
25天前
|
缓存 Python
Python 装饰器把函数"搞丢"了?5 个必踩的坑与完整避坑对照表
装饰器的坑不是"不会写",而是写完原函数被悄悄换掉——名字、文档、签名、身份都可能变。functools.wraps 救得回大部分,救不了全部。5 个坑逐个给复现代码和修法,附完整对照表。
|
8月前
|
人工智能 Linux API
OpenClaw全自动小红书运营实战:从0到1全流程部署、技能配置与内容自动化发布指南
在内容自动化运营场景中,OpenClaw(Clawdbot)凭借高度可扩展的Skill体系与多任务执行能力,可实现从热点追踪、文案创作、封面生成到笔记发布、互动管理的全流程自动化。本文基于2026年最新环境,完整讲解如何通过阿里云轻量服务器或本地Windows11/macOS/Linux部署OpenClaw,安装并配置小红书运营Skill,完成Cookie登录、内容生成、笔记发布、数据监控,并接入阿里云百炼Coding Plan免费大模型与QMD记忆优化系统,实现低成本、7×24小时无人值守小红书运营。全文无营销词汇,所有命令可直接复制,零基础用户也能快速跑通全流程。
3471 9
|
3月前
|
缓存 人工智能 自然语言处理
阿里云deepseek-v4-pro模型详解:模型能力、价格、上下文限制及使用注意事项参考
阿里云百炼平台提供的旗舰级MoE大模型DeepSeek-V4-Pro,该模型拥有1.6万亿总参数(激活49B),原生支持百万级超长上下文,在复杂推理、专业代码生成与长文本深度解析方面能力突出。文章详细梳理了其纯文本输入输出、支持Function Calling与结构化输出等核心功能,以及在华北2、新加坡、德国法兰克福、美国弗吉尼亚、日本东京五大区域的部署与功能差异。针对其超长上下文与深度思考模式,明确了该模型适用于复杂智能体开发、超长文档分析、高难度编程等高阶场景。
|
存储 算法 定位技术
Python计算经纬度坐标点距离:从原理到实战
本文详解Python实现地球两点间精确距离计算,涵盖Haversine与Vincenty公式、向量化优化及地理围栏等实战应用,助你掌握高精度球面距离算法。
1052 0
|
人工智能 安全 测试技术
信条:阿里云AI攻防安全启示录
解读AI时代下的安全攻防新态势
1795 12