← 返回题目列表

Python 里 True + True 等于几?为什么 bool 是 int 的子类?

中等 第 22 / 22 题 更新于 2026/07/28
Pythonboolint子类

简化版

**True + True == 2,因为 Python 里 boolint 的子类——True 本质就是整数 1False 就是整数 0,所以布尔值能直接参与算术运算。**关键事实:① isinstance(True, int)True(bool 继承自 int);② True == 1False == 0(值上完全相等),甚至 True == 1.0hash(True) == hash(1);③ 因此 True + True + True == 3sum([True, False, True]) == 2(统计满足条件的元素个数的常用技巧)、True * 5 == 5实用价值sum(x > 0 for x in nums) 能一行统计正数个数(每个布尔当 0/1 累加);["偶", "奇"][n % 2] 用布尔/整数当下标。但要注意的坑:① 因为 True == 1False == 0,字典里 {True: "a", 1: "b"} 会合并成一个键(1True 哈希相同、相等),最终只剩一项;② 判断「是否是布尔类型」要用 isinstance(x, bool),而且因为 bool 是 int 子类,isinstance(True, int) 也为真(要「只接受 int 不接受 bool」需额外排除)。核心记忆:bool 是 int 子类、True=1/False=0,能算术运算和当下标,但字典键会和 1/0 合并。

详细版

bool 与 int 的关系

事实结果
issubclass(bool, int)True(bool 继承 int)
isinstance(True, int)True
True == 1, False == 0True(值相等)
True + True2
sum([True, True, False])2
hash(True) == hash(1)True(能合并字典键)
print(True + True)          # 2
print(True + 1)             # 2
print(False - 1)            # -1
print(True * 5)             # 5
print(sum([True, False, True, True]))  # 3(统计 True 个数)
print(isinstance(True, int))    # True(bool 是 int 子类)
print(issubclass(bool, int))    # True

# 实用:一行统计满足条件的元素个数
nums = [3, -1, 5, -2, 0]
print(sum(n > 0 for n in nums))     # 2(正数个数)

# 布尔当下标
n = 7
print(["偶", "奇"][n % 2])          # 奇

# 坑:字典键合并(True==1, hash 相同)
d = {True: "a", 1: "b", 1.0: "c"}
print(d)                    # {True: 'c'} —— 三个键合并成一个!
print(len(d))               # 1

# 判断是否布尔类型
print(type(True) is bool)   # True
print(isinstance(True, bool))   # True
print(isinstance(1, bool))      # False(1 是 int 不是 bool)

⚠️ 理解这个知识点的关键是:Python 在设计布尔类型时,让 bool 继承 intTrue/False 就是特殊的 1/0),这是历史原因——Python 早期没有独立的布尔类型,一直用 1/0 表示真假,后来(2.3)加入 bool 时为了向后兼容(大量老代码用 1/0 做真假),就让它做 int 的子类。这带来了「布尔能当数字用」的便利(统计计数、当下标),但也埋了两个坑:① 字典/集合里 True1False0 会被当同一个键(因为它们 == 相等且 hash 相同),{1: "x", True: "y"} 只剩一项(键保留先出现的、值被后者覆盖);② 类型检查要小心——isinstance(True, int) 为真,如果一个函数「只想接受真正的整数、不接受布尔」(比如避免 func(True) 被当 func(1)),需要额外 and not isinstance(x, bool)。知道这个继承关系,很多「反直觉」现象就都通了。

完整版教学

一、bool 是 int 的子类

先确立核心事实:

核心事实:bool 继承自 int
  class bool(int): ...  (概念上)
  issubclass(bool, int) → True
  isinstance(True, int) → True

True 和 False 本质:
  True  就是整数 1(特殊的、显示为 True 的 1)
  False 就是整数 0(特殊的、显示为 False 的 0)

值上完全相等:
  True == 1        → True
  False == 0       → True
  True == 1.0      → True(跨类型数值比较)
  True is 1        → False(是同一个对象吗?不是,值相等≠同对象)

所以布尔能参与一切 int 能做的运算:
  算术:True + True = 2、True * 3 = 3
  比较:True > False(1 > 0)
  当下标:lst[True] = lst[1]
  位运算:True | False = 1

bool 覆盖了 int 的什么:
  主要是 __repr__/__str__(显示成 True/False 而非 1/0)
  以及 &、|、^(对两个 bool 返回 bool 而非 int)
  True & False → False(bool),但 True & 2 → 0(int)

所以 bool 是 int 子类,True=1/False=0,能做一切 int 运算

核心事实:bool 继承自 intissubclass(bool, int) 为 True、isinstance(True, int) 为 True)。True/False 本质:True 就是整数 1(显示为 True 的特殊 1)、False 就是整数 0。值上完全相等True == 1False == 0True == 1.0(跨类型数值比较),但 True is 1 为 False(值相等≠同对象)。所以布尔能参与一切 int 运算:算术(True+True=2)、比较(True>False)、当下标(lst[True]=lst[1])、位运算。bool 覆盖了 int 的 __repr__/__str__(显示成 True/False)以及 & | ^(对两个 bool 返回 bool)。理解「bool 是 int 子类(issubclass 为真);True=1/False=0 值上完全相等(True==1、==1.0,但 is 1 为假);能做一切 int 运算(算术/比较/下标/位运算);bool 覆盖了显示和 &|^」,就确立了核心事实。

二、True + True == 2 的原理

理解算术运算为什么成立:

True + True == 2 的原理:
  True 是 int 1 的实例(bool 继承 int)
  + 运算调用 int 的 __add__
  → 1 + 1 = 2(结果是 int 2,不是 bool)

一系列推论:
  True + True     = 2      (1+1)
  True + False    = 1      (1+0)
  True * 3        = 3      (1*3)
  False - 5       = -5     (0-5)
  True ** 2       = 1      (1**2)
  2 * True + 3 * False = 2 (2*1 + 3*0)

结果类型是 int(不是 bool):
  type(True + True) → int
  → 算术运算"退化"成普通整数(因为调的是 int 的方法)

sum 统计的妙用:
  sum([True, False, True, True])
  = 求和 = 1+0+1+1 = 3
  → 统计"True 的个数"= 统计"满足条件的元素个数"

  # 一行统计满足条件的元素数:
  count = sum(1 for x in data if cond(x))   # 传统
  count = sum(cond(x) for x in data)        # 布尔当 0/1(更简洁)

所以 True+True=2 因 bool 继承 int,+调 int 的__add__得 1+1=2(结果是 int)

True + True == 2 的原理:True 是 int 1 的实例(bool 继承 int)、+ 调用 int 的 __add__1+1=2(结果是 int 2 不是 bool)。一系列推论:True+False=1True*3=3False-5=-5True**2=1结果类型是 inttype(True+True) → int,算术运算「退化」成普通整数,因调的是 int 的方法)。sum 统计的妙用sum([True,False,True,True]) = 1+0+1+1 = 3——统计「True 的个数」= 统计「满足条件的元素个数」,sum(cond(x) for x in data)sum(1 for x in data if cond(x)) 更简洁。理解「True+True=2 因 bool 继承 int、+调 int 的__add__得 1+1=2(结果是 int 非 bool);sum([True,…])统计 True 个数=满足条件个数,sum(cond(x)for x in data)简洁」,就掌握了算术运算原理。

三、为什么这样设计——历史原因

理解 bool 继承 int 的历史缘由:

历史原因:
  ① Python 早期(<2.3)没有独立的布尔类型
     用整数 1/0 表示真假,条件判断、逻辑运算都用 1/0
     if x: ... 里 x 为真就是"非零"
  ② 大量老代码依赖 1/0 当真假:
     flag = 1  # 表示 True
     count += (a == b)  # a==b 返回 1/0 用于计数
  ③ Python 2.3 引入 bool 类型(True/False)
     为了"不破坏这些老代码",让 bool 做 int 的子类:
     True 仍能当 1 用、False 仍能当 0 用
     → 向后兼容:老代码 count += (a==b) 照常工作
        (a==b 现在返回 True/False,但等于 1/0)

设计权衡:
  好处:向后兼容 + "布尔当数字"的便利(计数、下标)
  代价:字典键合并、类型检查要小心(见后)

对比其他语言:
  强类型语言(Java):boolean 和 int 完全独立,不能相加
  Python:为了历史兼容和实用便利,选择 bool ⊂ int

设计哲学:"布尔就是特殊的整数"符合数学(真=1、假=0)
  也符合"能用就用、别过度限制"的实用主义

所以 bool 继承 int 是历史原因(早期用 1/0、2.3 加 bool 时为兼容),兼顾实用

历史原因① Python 早期(<2.3)没有独立布尔类型(用整数 1/0 表示真假、if x 里 x 为真就是「非零」);② 大量老代码依赖 1/0 当真假flag = 1count += (a == b) 用返回的 1/0 计数);③ Python 2.3 引入 bool 类型时为了「不破坏老代码」让 bool 做 int 的子类(True 仍能当 1、老代码 count += (a==b) 照常工作)。设计权衡:好处是向后兼容 + 「布尔当数字」的便利(计数、下标)、代价是字典键合并 + 类型检查要小心。对比:强类型语言(Java)boolean 和 int 完全独立、Python 为历史兼容和实用便利选择 bool ⊂ int。设计哲学:「布尔就是特殊的整数」符合数学(真=1、假=0)。理解「bool 继承 int 是历史原因:早期用 1/0、2.3 加 bool 时为兼容老代码(count+=(a==b))让 bool 做 int 子类;权衡兼容+便利 vs 字典键合并;Java 里 boolean 独立」,就理解了设计缘由。

四、实用价值——计数与下标

理解 bool 当数字的实用技巧:

实用技巧:

① 一行统计满足条件的元素个数(最常用):
   sum(x > 0 for x in nums)          # 正数个数
   sum(c.isdigit() for c in s)       # 数字字符个数
   sum(1 for x in data if cond)      # 传统写法(更啰嗦)
   → 布尔当 0/1 累加,简洁高效

② any / all 的关系:
   any(iterable) ≈ sum(bool)>0(有真)
   all(iterable) ≈ sum(bool)==len(全真)
   (any/all 有短路,更好;但理解上相通)

③ 布尔当下标选值(小技巧,慎用可读性):
   result = ["失败", "成功"][is_ok]   # is_ok=True→"成功"
   sign = [1, -1][x < 0]              # x<0→-1 否则 1
   ⚠️ 可读性不如三元 "成功" if is_ok else "失败",看情况用

④ 矩阵/网格计数:
   live = sum(sum(row) for row in grid)  # grid 是 0/1 矩阵,数 1

⑤ 加权计数:
   score = 3*passed + 1*attended  # passed/attended 是布尔

对比 numpy:
  np.array([True,False,True]).sum() → 2(同理,布尔当 0/1)
  布尔数组做掩码计数是 numpy 核心用法

所以实用:sum(cond for x in data)一行计数、布尔当下标选值、加权计数

实用技巧① 一行统计满足条件的元素个数(最常用)sum(x > 0 for x in nums)(正数个数)、sum(c.isdigit() for c in s)(数字字符个数)——布尔当 0/1 累加,比 sum(1 for x in data if cond) 简洁;② any/all 的关系any ≈ sum(bool)>0all ≈ sum(bool)==len(any/all 有短路更好);③ 布尔当下标选值["失败","成功"][is_ok][1,-1][x<0],可读性不如三元、慎用);④ 矩阵/网格计数sum(sum(row) for row in grid) 数 1);⑤ 加权计数3*passed + 1*attended)。对比 numpy:布尔数组做掩码计数是核心用法。理解「实用:①sum(cond for x in data)一行统计满足条件个数(布尔当 0/1)②any/all 关系③布尔当下标选值(慎用可读性)④网格计数⑤加权计数;numpy 布尔掩码同理」,就掌握了实用价值。

五、两个坑——字典键合并与类型检查

理解 bool 是 int 子类带来的两个坑:

坑1:字典/集合里 True 和 1、False 和 0 合并

  因为 True == 1 且 hash(True) == hash(1)
  → 字典视它们为"同一个键"

  d = {True: "a", 1: "b"}
  → {True: "b"}  (只剩一个键!)
     键保留"先出现的"(True),值被"后出现的"(b)覆盖

  d = {1: "x", True: "y", 1.0: "z"}
  → {1: "z"}  (1、True、1.0 全合并,因值相等 hash 相同)

  集合同理:
  {True, 1, 1.0} → {True}(合并成一个元素)
  {False, 0} → {False}

  实战风险:
  用布尔和整数混当字典键 → 意外合并、数据丢失
  → 别混用;需要区分就转成不同类型的键

坑2:类型检查——isinstance(True, int) 为真

  isinstance(True, int)   → True(bool 是 int 子类)
  → 想"只接受 int、拒绝 bool"时会误放行 True

  def process(n):
      if not isinstance(n, int):   # True 也通过!
          raise TypeError
      ...
  process(True)   # 被当 int 1 处理(可能不是你想要的)

  精确判断:
  只要 bool:       isinstance(x, bool)
  只要 int 非 bool: isinstance(x, int) and not isinstance(x, bool)
  只要精确 int 类型: type(x) is int(不含子类)

所以两坑:①字典键 True/1、False/0 合并(hash 相等)②isinstance(True,int)为真(类型检查要排除 bool)

坑1:字典/集合里 True 和 1、False 和 0 合并——因 True == 1hash(True) == hash(1)、字典视它们为「同一个键」:{True: "a", 1: "b"}{True: "b"}(只剩一个键,键保留先出现的 True、值被后者 b 覆盖),{1:"x", True:"y", 1.0:"z"}{1:"z"}(全合并),集合同理 {True,1,1.0}{True}。实战风险:布尔和整数混当字典键会意外合并、数据丢失。坑2:类型检查——isinstance(True, int) 为真(bool 是 int 子类),想「只接受 int 拒绝 bool」时会误放行 True。精确判断:只要 bool 用 isinstance(x, bool)、只要 int 非 bool 用 isinstance(x, int) and not isinstance(x, bool)、只要精确 int 类型用 type(x) is int。理解「两坑:①字典/集合里 True/1、False/0 合并(hash 相等值相等,键保留先出现值被覆盖)②isinstance(True,int)为真(要排除 bool 用 and not isinstance(x,bool)或 type(x)is int)」,就掌握了两个坑。

六、总结与实践

总结 bool 与 int 的关系:

核心事实:
  bool 是 int 的子类(历史原因:早期用 1/0、2.3 加 bool 时为兼容)
  True = 1、False = 0(值上完全相等)
  能做一切 int 运算(算术、比较、下标、位运算)

便利(用起来):
  sum(cond for x in data)  一行统计满足条件个数
  布尔当下标、加权计数、网格数 1

坑(要小心):
  ① 字典/集合键:True 和 1、False 和 0 合并(别混用)
  ② 类型检查:isinstance(True, int) 为真
     只要 int 非 bool → and not isinstance(x, bool)

判断类型速查:
  是布尔吗          isinstance(x, bool)
  是 int(含 bool)  isinstance(x, int)
  是 int 非 bool     isinstance(x,int) and not isinstance(x,bool)
  精确是 int         type(x) is int

其他数值类型的类似关系:
  int ⊄ float(int 不是 float 子类,但 int 能自动转 float)
  bool ⊂ int ⊂ (数值塔 Number)
  → 只有 bool⊂int 这一层是"子类"关系

核心总结:
  True+True==2 因 bool⊂int(True=1)
  便利:sum 计数、当下标
  坑:字典键合并、类型检查要排除 bool

所以 bool⊂int(True=1/False=0),便利计数/下标,坑字典键合并+类型检查

核心事实:bool 是 int 的子类(历史原因)、True=1/False=0(值上完全相等)、能做一切 int 运算。便利sum(cond for x in data) 一行统计、布尔当下标、加权计数、网格数 1。:① 字典/集合键 True 和 1、False 和 0 合并(别混用)、② 类型检查 isinstance(True, int) 为真(只要 int 非 bool 要 and not isinstance(x, bool))。判断类型速查:是布尔 isinstance(x, bool)、是 int 含 bool isinstance(x, int)、是 int 非 bool 加 and not isinstance(x, bool)、精确 int type(x) is int。理解「bool⊂int(True=1/False=0)能做 int 运算;便利 sum 计数/下标;坑字典键合并+类型检查要排除 bool;判断类型 isinstance(x,bool)/type(x)is int」,就掌握了总结与实践。

记忆钩子:「True+True==2 因为 bool 是 int 的子类(issubclass(bool,int)为真、isinstance(True,int)为真)——True 本质就是整数 1、False 就是 0,值上完全相等(True==1、==1.0,但 is 1 为假),所以能参与一切 int 运算(算术 True*3=3、比较 True>False、当下标 lst[True]、位运算);★这是历史原因:Python 早期(<2.3)没独立布尔类型、用 1/0 表真假,2.3 加 bool 时为兼容大量老代码(count+=(a==b))让 bool 做 int 子类;便利:sum(cond for x in data)一行统计满足条件的元素个数(布尔当 0/1 累加)、布尔当下标选值、加权计数;两个坑:①字典/集合里 True 和 1、False 和 0 会合并成一个键(因==相等且 hash 相同,键保留先出现值被后者覆盖,{True:‘a’,1:‘b’}只剩{True:‘b’})②类型检查 isinstance(True,int)为真,想只要 int 不要 bool 得 and not isinstance(x,bool)或 type(x)is int」

七、常见误区与追问

  • 误区:bool 和 int 是完全独立的类型。 不是——boolint 的子类(issubclass(bool, int) 为 True),True 本质就是整数 1、False 就是 0,值上完全相等(True == 1False == 0、甚至 True == 1.0),所以布尔能直接参与算术运算(True + True == 2)、比较、当下标;这和 Java 等强类型语言里 boolean 和 int 完全独立不同。
  • 误区:True + True 会报类型错误。 不会——因为 bool 继承 int,True + True 等价于 1 + 1 = 2(结果类型是 int 不是 bool);这个特性常被用来一行统计满足条件的元素个数:sum(x > 0 for x in nums) 就是把每个布尔当 0/1 累加得到正数个数。
  • 误区:字典里 True 和 1 是两个不同的键。 是同一个键——因为 True == 1hash(True) == hash(1),字典和集合都把它们当同一个键,{True: "a", 1: "b"} 最终只剩一项 {True: "b"}(键保留先出现的 True、值被后出现的 b 覆盖);{1: "x", True: "y", 1.0: "z"} 三个键全合并成一个;所以别在字典/集合里混用布尔和整数(0/1)当键,会意外合并、丢数据。
  • 误区:用 isinstance(x, int) 就能确保 x 不是布尔。 不能——因为 bool 是 int 子类,isinstance(True, int) 返回 True,布尔值会通过 isinstance(x, int) 检查;如果你的函数「只想接受真正的整数、要拒绝布尔」(避免 func(True) 被悄悄当 func(1)),需要额外判断:isinstance(x, int) and not isinstance(x, bool),或者用 type(x) is int(精确类型、不含子类)。
  • 追问:为什么 Python 要让 bool 继承 int(而不是做成独立类型)? 历史兼容原因:Python 早期(2.3 之前)根本没有独立的布尔类型,一直用整数 1 和 0 来表示真和假,大量代码依赖这个约定——比如 count += (a == b) 用比较返回的 1/0 来计数、flag = 1 表示开关;到 Python 2.3 引入 True/False 时,为了不破坏这些已有代码,就让 boolint 的子类,使 True 仍然能当 1 用、False 当 0 用,老代码照常工作;这个设计也顺带带来了「布尔能当数字用」的实用便利(计数、下标),符合「真=1、假=0」的数学直觉。
  • 追问:sum([True, False, True]) 为什么等于 2,这有什么实用价值? 因为 bool 是 int 子类、True=1/False=0,sum 对它们求和就是 1 + 0 + 1 = 2,即统计了列表里 True 的个数;实用价值是「一行统计满足某条件的元素个数」:sum(x > 0 for x in nums) 数正数、sum(c.isspace() for c in text) 数空白字符、sum(sum(row) for row in grid) 在 0/1 矩阵里数 1;这比 sum(1 for x in nums if x > 0) 或写显式循环更简洁,是 Python 里很常见的计数惯用法(numpy 里布尔数组 .sum() 做掩码计数也是同理)。
  • 追问:怎么精确判断一个值「是布尔」还是「是整数但不是布尔」? ① 判断「是布尔」:isinstance(x, bool)type(x) is bool;② 判断「是整数(可以包含布尔)」:isinstance(x, int)(注意 True/False 也会返回 True,因为是子类);③ 判断「是整数但不是布尔」:isinstance(x, int) and not isinstance(x, bool),或者用 type(x) is int(精确类型判断、不匹配子类,所以 True 会返回 False);实际写库/校验参数时,如果不希望布尔被当整数处理,就要用后两种方式显式排除 bool。

八、加强记忆

True + True == 2,因为 boolint 的子类issubclass(bool, int) 为 True、isinstance(True, int) 为 True)——True 本质就是整数 1、False 就是 0,值上完全相等(True == 1True == 1.0,但 True is 1 为 False),所以能参与一切 int 运算(算术 True*3=3、比较 True>False、当下标 lst[True]、位运算)。这是历史原因:Python 早期(<2.3)没有独立布尔类型、用 1/0 表真假,2.3 引入 bool 时为兼容大量老代码(count += (a==b))让 bool 做 int 子类。便利sum(cond for x in data) 一行统计满足条件的元素个数(布尔当 0/1 累加)、布尔当下标选值、加权计数。两个坑① 字典/集合里 True1False0 会合并成一个键(因 == 相等且 hash 相同,键保留先出现的、值被后者覆盖,{True:"a", 1:"b"} 只剩 {True:"b"});② 类型检查 isinstance(True, int) 为真,想「只要 int 不要 bool」得 isinstance(x, int) and not isinstance(x, bool)type(x) is int。一句话「bool⊂int(True=1/False=0、值上完全相等),能做一切 int 运算,是历史兼容原因;便利 sum 一行计数(布尔当 0/1)/当下标;坑字典键 True 和 1 合并、类型检查 isinstance(True,int)为真要额外排除 bool」。