# 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
```
