You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么CPython返回True/False单例新指针并增加其引用计数?

Python布尔单例的引用计数困惑解答

布尔类型的单例特性

Python中的布尔类型是整数的子类,仅存在Py_False和Py_True两个布尔对象。

Py_False和Py_True分别对应Python层面False和True的单例,你可以通过以下代码验证:

a = True
b = True
a is b  # 返回True

False的表现完全一致。

CAPI中的布尔对象处理

在Python的C实现中,PyBool_FromLong方法负责从long类型创建布尔对象,代码如下:

PyObject *PyBool_FromLong(long ok)
{
    PyObject *result;

    if (ok)
        result = Py_True;
    else
        result = Py_False;
    return Py_NewRef(result);
}

它会返回指向对应单例的指针,但返回前会调用Py_NewRef增加对象的引用计数。

同时,Py_True和Py_False的定义也明确标注了规则:

/* Py_False and Py_True are the only two bools in existence.
Don't forget to apply Py_INCREF() when returning either!!! */

/* Don't use these directly */
PyAPI_DATA(PyLongObject) _Py_FalseStruct;
PyAPI_DATA(PyLongObject) _Py_TrueStruct;

/* Use these macros */
#define Py_False _PyObject_CAST(&_Py_FalseStruct)
#define Py_True _PyObject_CAST(&_Py_TrueStruct)

注释强制要求返回这两个对象时必须增加引用计数,PyBool_FromLong也严格遵循了这个要求。

核心疑问与解答

疑问:既然是不会被垃圾回收的单例,为何需要维护引用计数?

这本质是Python C API统一的内存管理规则,和对象是否为单例无关:

  • C API的硬性约定是:任何通过API返回的对象引用,都必须是一个“调用者拥有的引用”——调用者需要负责在不再使用时调用Py_DECREF释放引用。
  • 哪怕是单例对象,也得遵守这个规则。如果返回时不增加引用计数,调用者后续调用Py_DECREF会导致引用计数变为负数,触发内存错误或破坏解释器的引用计数系统。
  • 单例的“不会被回收”是因为它们的初始引用计数被设置为极大值(或解释器做了特殊保护),但日常的引用增减仍要遵循通用规则,保证整个引用计数系统的一致性。
  • 举个实际场景:如果某个函数返回Py_True时不递增引用计数,调用者拿到引用后调用Py_DECREF,会让Py_True的引用计数错误减少,虽然不会真的被回收,但会破坏引用计数的准确性,可能导致其他依赖该计数的逻辑出现异常。

内容的提问来源于stack exchange,提问作者EJoshuaS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 20:05:16