# 12.5 布尔和整数类型

`bool` 类型是内置类型中最直接的实现。它继承自 `long`，并且有预定义的常量，`Py_True` 和 `Py_False`。这些常量是\*\*不可变（immutable）\*\*实例，在 Python 解释器的初始化过程中创建。

在 `Objects/boolobject.c` 中，你可以看到从整数创建 `bool` 类型实例的辅助函数。

`Objects/boolobject.c` 第 28 行

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

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

这个函数使用 C 语言对一个整数进行判断，`result` 结果为 `Py_True` 或 `Py_False`，最后把 `result` 的引用计数加一。

`bool` 类型实现了 `and`、`xor` 和 `or` 操作对应的数值函数，但在从 `long` 继承的过程中删除了加法、减法和除法，因为将两个布尔值相除是没有意义的。

对于 `bool`，`and` 的实现首先检查 `a` 和 `b` 是否是 `bool` 值。如果不是，它们被转成整数，然后对这两个整数进行和运算。

`Objects/boolobject.c` 第 61 行

```c
static PyObject *
bool_and(PyObject *a, PyObject *b)
{
    if (!PyBool_Check(a) || !PyBool_Check(b))
        return PyLong_Type.tp_as_number->nb_and(a, b);
    return PyBool_FromLong((a == Py_True) & (b == Py_True));
}
```

## `long`类型

`long` 类型比 `bool` 类型稍微复杂一点。在从 Python 2 迁移到 Python 3 的过程中，CPython 抛弃了对 `int` 类型的支持，并且使用 `long` s作为主要的整数类型。

Python 的 `long` 类型比较特别，它可以存储长度可变的整数。最大长度被设置在编译出来的二进制文件中。

Python `long` 数据结构由 `PyObject_VAR_HEAD` 和一个数字数组组成。数字数组 `ob_digit` 最开始长度为 1，在初始化时它可以扩展到更长的长度。

`Include/longintrepr.h` 第85行

```c
struct _longobject {
    PyObject_VAR_HEAD
    digit ob_digit[1];
};
```

比如，整数 1 为 `ob_digits [1]`，整数 24601 为 `ob_digits [2, 4, 6, 0, 1]`。

内存通过 `_PyLong_New()` 分配给一个新的 `long`。这个函数接收一个固定的长度，并确保它小于 `MAX_LONG_DIGITS`。

然后它为 `ob_digit` 重新分配内存，使之与这个长度相匹配。

为了将 C 语言的 `long` 类型转换为 Python 语言的 `long` 类型，首先 C 语言的 `long` 被转换为一个数字列表，然后为 Python 语言的 `long` 分配内存，最后设置每个数字。

对于个位数的数字，`long` 对象将使用长度为 1 的 `ob_digit` 进行初始化。然后，在不分配内存的情况下设置数值。

`Objects/longobject.c` 第 297 行

```c
PyObject *
PyLong_FromLong(long ival)
{
    PyLongObject *v;
    unsigned long abs_ival;
    unsigned long t;
    /* unsigned so >> doesn't propagate sign bit */
    int ndigits = 0;
    int sign;
    CHECK_SMALL_INT(ival);
    ...
    /* Fast path for single-digit ints */
    if (!(abs_ival >> PyLong_SHIFT)) {
        v = _PyLong_New(1);
        if (v) {
            Py_SIZE(v) = sign;
            v->ob_digit[0] = Py_SAFE_DOWNCAST(
                abs_ival, unsigned long, digit);
        }
        return (PyObject*)v;
    }
...
    /* Larger numbers: loop to determine number of digits */
    t = abs_ival;
    while (t) {
        ++ndigits;
        t >>= PyLong_SHIFT;
    }
    v = _PyLong_New(ndigits);
    if (v != NULL) {
        digit *p = v->ob_digit;
        Py_SIZE(v) = ndigits*sign;
        t = abs_ival;
        while (t) {
            *p++ = Py_SAFE_DOWNCAST(
            t & PyLong_MASK, unsigned long, digit);
            t >>= PyLong_SHIFT;
        }
    }
    return (PyObject *)v;
}
```

如果想把一个双精度浮点数转换为 Python `long` 类型，可以使用 `PyLong_FromDouble()`，它为你做了相关数学计算。

在 `Objects/longobject.c` 中的其余函数都有各自的功能，比如 `PyLong_FromUnicodeObject()` 可以将 `Unicode` 字符串转换为数字。

## 例子

`long` 的 rich-comparison 的类型槽被设置为 `long_richcompare()`。这个函数封装了`long_compare()`。

`Objects/longobject.c` 第3031行

```c
static PyObject *
long_richcompare(PyObject *self, PyObject *other, int op)
{
    Py_ssize_t result;
    CHECK_BINOP(self, other);
    if (self == other)
        result = 0;
    else
        result = long_compare((PyLongObject*)self, (PyLongObject*)other);
    Py_RETURN_RICHCOMPARE(result, 0, op);
}
```

`long_compare()` 将首先检查两个变量 `a` 和 `b` 的长度（位数），如果长度相同，那么它将遍历每个数字，看它们是否相互相等。

`long_compare()` 返回以下三种结果之一。

1. 如果 `a < b`，那么它返回一个负数。
2. 如果 `a == b`，那么它返回 `0`。
3. 如果 `a > b`，那么它返回一个正数。

比如执行 `1 == 5`，结果是 `-4`。 对于 `5 == 1`，结果则是 `4`。

你可以在 `Py_RETURN_RICHCOMPARE` 宏之前实现以下代码块，以在结果的绝对值 `<=1` 时返回 `True`。 它使用宏 `Py_ABS()` 返回有符号整数的绝对值：

```c
    if (op == Py_AlE) {
        if (Py_ABS(result) <= 1)
            Py_RETURN_TRUE;
        else
            Py_RETURN_FALSE;
    }
    Py_RETURN_RICHCOMPARE(result, 0, op);
}
```

重新编译 Python 后，你可以看到改动后的效果：

```python
>>> 2 == 1
False
>>> 2 ~= 1
True
>>> 2 ~= 10
False
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hai-shi.gitbook.io/cpython-internals/12-objects-types/12.5-the-bool-and-long-type.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
