Python bool 为何是 int 的子类

3次阅读

True 和 False 是 int子类,底层值为 1 和 0,支持所有整数操作但语义上应避免滥用;type(True) is int 为 False,isinstance(True, int) 为 True;json 序列化会丢失类型信息。

Python bool 为何是 int 的子类

为什么 isinstance(True, int) 返回 True

因为 boolpython 中确实是 int 的子类,不是语法糖或兼容性补丁,而是 CPython 源码里明确定义的继承关系。这决定了 TrueFalse 本质是 int 的两个特例实例。

实操上要注意:所有对 int 成立的操作(比如加减、格式化、位运算),对 bool 都合法——但不意味着应该这么做。

  • True + 1 得到 2False * 1000,这不是 bug,是设计使然
  • bool__repr____str__ 被重写成显示 True/False,但底层值仍是 10
  • type(True) is int 判断会失败(返回 False),必须用 isinstance(True, int)

issubclass(bool, int) 为真,但 bool 为何只有两个值

子类不等于“可扩展”。bool 类在初始化时强制拦截所有输入,只允许生成 TrueFalse

bool(2)   # → True   bool(-1)  # → True   bool(0)   # → False

它复用了 int 的数值行为,但封死了构造任意整数实例的路径。

立即学习Python免费学习笔记(深入)”;

  • bool__new__ 方法直接调用 int.__new__,但传入的值被 __bool__ 逻辑归约成 01
  • 你无法通过继承 bool 创建第三个布尔值,class TriBool(bool): pass 不会改变这个限制
  • 这种设计让 if x:x and y 等逻辑操作能复用已有的整数比较与短路规则,无需额外实现

在类型提示和运行时检查中容易误判的地方

静态类型检查器(如 mypy)通常把 bool 当作独立类型处理,但运行时 isinstance(x, int)bool 实例返回 True,这会导致不一致。

  • def f(x: int) -> None: 时,传入 True 不会触发 mypy 报错(mypy 默认允许 boolint 协变)
  • 但若函数内部做了 assert isinstance(x, int) and not isinstance(x, bool),这种判断是错的——bool 就是 int 的子类
  • 真正安全的类型区分方式是:type(x) is bool(精确匹配),或 isinstance(x, bool)(含子类,但 bool 没有公开子类)

实际项目里该不该依赖 boolint 子类

可以读,不要写;可以观察,不要利用。

  • int(True) 转换没问题,这是明确支持的隐式转换
  • 但避免写 if x == 1: 来判断布尔值——它在 x = True 时成立,但语义模糊,且当 x = 1(纯整数)时也会误触发
  • 序列索引中用 my_list[flag]flagbool)是常见且安全的,因为 True 就是 1False 就是 0,但前提是列表长度 ≥ 2
  • 最易忽略的坑:JSON 序列化时 True 变成 true(小写),而 int(True)1,序列化后变成数字 1——类型信息彻底丢失

text=ZqhQzanResources