Python 的 True + True 为什么等于 2?bool 是 int 子类,这个设计坑了多少人

简介: True+True==2、isinstance(True,int) 为真:bool 是 int 的子类,True 就是 1。9 组实验讲透这个 C 时代设计遗产的顺手与埋雷——字典键碰撞、JSON 序列化、== 与 is 混用三大坑一次避开。

结论先行:在 Python 里 True + True == 2,sum([True, False, True]) == 2,isinstance(True, int) 直接返回 True——因为 bool 根本不是独立类型,它是 int 的子类,True 就是 1,False 就是 0。这个设计是从 C 语言时代继承下来的,用起来极其顺手,也极其容易埋雷:字典键碰撞、JSON 序列化、== 与 is 的混用,三个坑几乎每个项目都踩过。这篇用 9 组实验把这个「设计选择」和它的「代价」一次讲透。


1. 先看一组反常识的实验结果

>>> True + True
2
>>> True * 3
3
>>> isinstance(True, int)
True
>>> bool.__mro__
(<class 'bool'>, <class 'int'>, <class 'object'>)

很多人第一次见到 True + True 的结果是懵的:布尔值不是「真」和「假」吗,怎么能相加?

但在 Python 的对象模型里,True 和 False 不是「状态」,而是两个「数」。它们长这样:

>>> True == 1
True
>>> False == 0
True
>>> int(True), int(False)
(1, 0)

True 就是 1 的马甲,False 就是 0 的马甲。既然如此,True + True 等于 2 还有什么可奇怪的吗?

2. bool 是什么:类型继承链一张表

bool 的类型继承链说明了一切:

bool -> int -> object
维度 bool int
继承关系 继承自 int 继承自 object
实例个数 全局只有两个:True、False 无限个
可否相加 可以(结果按 int 算) 可以
内存表示 指向 1 和 0 的单例 任意精度整数对象
创建新实例 bool(0) 仍返回 False 单例 int(x) 每次产生新对象

注意最后一行:bool 是单例类型。bool(0)、bool(False)、bool([]) 拿到的都是同一个 False 对象:

>>> bool(0) is bool(False) is False
True

这和 int 不一样。int 的小整数(-5 到 256)有缓存,但大整数每次运算都产生新对象;而 bool 从语言设计上就锁死了只有两个实例。

3. 为什么这样设计:C 语言的账

Python 的 bool 是 2001 年才引入的(PEP 285,Python 2.3),在那之前,「真」「假」就是用 1 和 0 表示的——和 C 语言一脉相承。

但 PEP 285 没有把 bool 设计成 int 的「兄弟」类型,而是设计成了子类,理由很务实:

  • 兼容性。引入 bool 之前,全世界的代码都在写 return 1 表示成功。如果 bool 和 int 再无关系,flag == 1 这种写法会大面积失效,老代码会崩。
  • C 扩展的便利。底层 PyBoolObject 结构体就是在 PyLongObject 基础上封装的,C 代码里可以直接按整数读写。
  • 语义。布尔值本质上是「非假即真」的二值,而整数天然覆盖这两个值,复用整数运算不需要新造一套规则。

代价是:True 从此永远背着 1 的数学身份,甩不掉了。

4. 第一个坑:字典和集合里的键碰撞

因为 True == 1 且 hash(True) == hash(1),在字典里它们是同一个键:

>>> d = {
   }
>>> d[True] = "布尔键"
>>> d[1] = "整数键"
>>> d
{
   True: '整数键'}

你以 True 为键存了值,再用 1 去取,取到的是同一个槽位——第二次赋值直接覆盖了第一次。反过来也一样:

>>> {
   True: "a", 1: "b", 1.0: "c"}
{
   True: 'c'}

连 1.0 都来抢这个键,因为 1.0 == True 且三者哈希值相同。

实际项目里这种坑常出现在计数器和去重集合上:你以为集合里有 True 和 1 两个元素,其实只有一个:

>>> len({
   True, 1, 1.0})
1

5. 第二个坑:JSON 序列化的静默变形

json 模块序列化布尔值时当然输出 true/false,这是符合规范的。但反序列化回来的 1 不会变成 True:

>>> import json
>>> json.dumps({
   "flag": True})
'{"flag": true}'
>>> json.loads('{"flag": 1}')
{
   'flag': 1}
>>> json.loads('{"flag": 1}')["flag"] == True
True   # 相等,但不是同一个东西

麻烦在于相等:前端传 {"flag": 1},后端 if data["flag"]: 判断照样通过,类型检查却过不了;再传给严格的校验库(如 pydantic 开启严格模式)直接报错。更隐蔽的是 sum 类聚合:

>>> json.loads('[true, false, true]')
[True, False, True]
>>> sum([True, False, True])
2

一个「布尔列表」求和得到 2——这在业务代码里经常是 bug 而不是 feature。

6. 第三个坑:== 和 is 的混用

True == 1 为真,但 True is 1 为假:

>>> True == 1
True
>>> True is 1
False

is 判断的是对象身份。True 是 bool 单例,1 是 int 对象(小整数缓存里的那个),两者不是同一个对象。

这意味着判断「是不是布尔值」不能用 == 1:

>>> (1 == True) is True
True
>>> isinstance(1, bool)   # 正确写法
False
>>> isinstance(True, bool)  # 正确写法
True

反过来,判断「是不是真值」要用 is True 或直接 if,不要写 if x == 1——否则 1、1.0、True、Decimal(1) 全都混进来。这是静态类型检查工具(mypy/pyright)反复强调的规矩。

7. bool 的「假值」远不止 False

因为 bool() 接受任何对象,而每个对象都有「真假值」:

>>> bool(0), bool(""), bool([]), bool(None)
(False, False, False, False)
>>> bool(0.0), bool({
   }), bool(set())
(False, False, False)

注意:bool 的子类身份不影响这个语义。空列表不是 0,但它「假」。判断规则是:对象实现了 __bool__ 就用它,否则用 __len__,两者都没有就为真。这套规则和 bool 继承 int 无关,属于另一套协议——不要混为一谈。

8. 想不用 bool,可能吗

有人想过:要是 bool 不继承 int 会怎样?

答案是生态会崩一半。C 扩展、NumPy、数据库驱动、protobuf 生成的代码里,True 到处被当 1 用:

>>> import numpy as np
>>> np.array([True, False, True]).sum()
2
>>> np.array([True, False, True]).dtype
dtype('bool')

NumPy 里 bool 数组是独立 dtype,但 sum() 出来的还是 2——因为整个数值生态都建立在「布尔即整数」之上。想改,得先问过二十年的存量代码。

9. 一张速查表收尾

写法 结果 说明
True + True 2 布尔按整数运算
True == 1 True 值相等
True is 1 False 对象不同
isinstance(True, int) True bool 是 int 子类
{True: 1, 1: 2} {True: 2} 键碰撞,后者覆盖
sum([True, False]) 1 布尔列表求和
json.loads('{"f":1}')["f"] 1(int) JSON 反序列化不还原 bool

一句话总结:bool 继承 int 是 Python 为兼容 C 时代存量代码做的务实妥协,True 就是 1、False 就是 0 是特性不是 bug;但在写字典键、JSON 边界和类型判断时,必须记住这个「马甲设定」,该用 isinstance 就别用 ==,该用 is True 就别用 == 1。

相关文章
|
2天前
|
云安全 人工智能 运维
当攻击全面Agent化,你的安全防御能否跟上AI Speed?
多起客户侧AK泄露事件应急的真实观察
1210 2
|
26天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
9617 32
|
12天前
|
存储 人工智能 并行计算
大模型本地部署终端选型方法论:以 Qwen3.8-27B 为例的四档分层完整流程
本文提出一套大模型本地部署终端选型方法论:定约束、定档位、定框架、定参数四步决策法,配合入门、主力、质量、无损四档分层模型。以 Qwen3.8-27B 实测数据为例,逐环节解读显存、带宽、存储、散热、系统、预算等要素,给出面向不同预算的优选方案、决策自查清单与市场观察框架。文末前瞻 AI 笔记本的 CPU+GPU 与统一内存两条路线,论证四步决策法在新品类上的延续性。
|
10天前
|
人工智能 JSON 自然语言处理
2026 年 Jev 决策模型深度拆解:原理解读、实战测评与保姆级落地教程
有一款特殊AI模型在开发者圈子刷屏,它摒弃传统大模型擅长的对话聊天能力,专注做高速结构化决策,它就是TypeSafe AI推出的Jev模型。该模型由ChatGPT共同发明人Diogo Almeida主导研发,定位为**System One Model(系统一模型)**,对标人类大脑快速直觉判断的思维模式,在响应延迟、调用成本、结构化输出稳定性上相比传统生成式大模型有着巨大差异。本文会完整拆解Jev底层原理、三大核心原语能力、适用业务场景,同时提供可直接运行的curl、Python代码示例,并且结合多组实测数据,客观分析模型优势与能力边界,帮助普通开发者和AI应用从业者快速上手落地。
814 1
|
7天前
|
人工智能 JSON 自然语言处理
2026 年 Jev 决策模型全解析:核心原理拆解,性能实战测评与落地部署教程
有一款特殊AI模型在开发者圈子刷屏,它摒弃传统大模型擅长的对话聊天能力,专注做高速结构化决策,它就是TypeSafe AI推出的Jev模型。该模型由ChatGPT共同发明人Diogo Almeida主导研发,定位为System One Model(系统一模型),对标人类大脑快速直觉判断的思维模式,在响应延迟、调用成本、结构化输出稳定性上相比传统生成式大模型有着巨大差异。本文会完整拆解Jev底层原理、三大核心原语能力、适用业务场景,同时提供可直接运行的curl、Python代码示例,并且结合多组实测数据,客观分析模型优势与能力边界,帮助普通开发者和AI应用从业者快速上手落地。
538 0
|
3天前
|
Web App开发 人工智能 JavaScript
太猛了,一个月干到15W+,给大家推荐一个最近爆火的开源逆向工具:REA
REA(Reverse Engineer Anything)是近期爆火的开源AI逆向工具,4月发布,1个月内斩获15万+ Star。它让AI Agent无需源码即可分析二进制、APK、JS/Electron、HAR包等17类目标,自动反编译、生成可运行代码,并强制返回带证据与局限的结论。全本地执行,MIT协议,支持Hopper/Ghidra/IDA等引擎,一行命令即可上手。
464 0
太猛了,一个月干到15W+,给大家推荐一个最近爆火的开源逆向工具:REA
|
8天前
|
存储 人工智能 自然语言处理
千问办公官网入口链接在哪?2026年最新QwenWork测评、千问办公怎么样?一文看懂
千问办公(QwenWork)是阿里云推出的AI智能办公平台,提供网页端和阿里云官网双入口。支持PPT/Word/Excel生成、多模态处理、网页全栈搭建、钉钉深度集成等6大核心能力。个人版免费可用,高级版198元/月;企业版198元/人/月。新用户注册即赠2000积分。阿里千问办公QwenWork官网:https://t.aliyun.com/U/0VCTGt 阿里AI工作平台,一句话完成数据分析、PPT 生成、视频剪辑、网页搭建等复杂任务
1077 0
|
6天前
|
存储 人工智能 安全
千问办公官网入口网页版登录:qwenwork.cn 注册送2000积分、登录送100积分
阿里云千问办公(QwenWork)是AI智能工作平台,支持一句话生成PPT、表格、网页、视频及数据分析。个人免费版送2000积分+每日登录赠100分,含1GB存储、5个发布页;企业版198元/席/月起。阿里千问办公QwenWork官网:https://t.aliyun.com/U/0VCTGt 阿里AI工作平台,一句话完成数据分析、PPT 生成、视频剪辑、网页搭建等复杂任务