古明地觉的编程教室

Python 的 None 是怎么实现的?

Image

楔子

本篇文章来聊一聊 None 是怎么实现的,None 在 Python 里面也是一个对象,用于表示空(值不存在的情况)。比如基于主键从数据库获取记录,如果没有查询到,那么一般会返回 None。

另外如果函数没有返回值,那么会隐式地返回 None,表示返回的是空。

Image

None 的底层结构

和其它对象不同,由于 None 没有额外的实体数据,所以它在底层就是一个 PyObject 结构体实例。因此也能看出,None 的大小为 16 字节。

// Objects/object.c
PyObject _Py_NoneStruct = {
    _PyObject_EXTRA_INIT
    { _Py_IMMORTAL_REFCNT },
    &_PyNone_Type
};

None 在底层只包含引用计数和类型,引用计数为 2 ** 32 - 1,所以 None 是一个永恒对象,然后类型为 _PyNone_Type。由于变量都是 PyObject *,所以和布尔值一样,解释器也提供了相应的宏,从而方便使用。

// Include/object.h
#define Py_None (&_Py_NoneStruct)

注意:None 是单例的,如果要判断对象是否为空,应该使用 is 关键字。

// Objects/object.c
// Python 虽然一切皆对象,但你能拿到的都是对象的指针
// 所以变量本质上就是指针,但操作变量时会自动操作变量指向的内存
// 而 is 用于判断两个变量是否引用同一个对象
// 那么底层只需要判断这两个变量保存的地址是否相同即可
int Py_Is(PyObject *x, PyObject *y)
{
    // 所以 is 在底层就是一个 == 判断
    return (x == y);
}

// x is None,只需判断 x 保存的地址和 Py_None 是否相同
int Py_IsNone(PyObject *x)
{
    return Py_Is(x, Py_None);
}

// x is True,只需判断 x 保存的地址和 Py_True 是否相同
int Py_IsTrue(PyObject *x)
{
    return Py_Is(x, Py_True);
}

// x is False,只需判断 x 保存的地址和 Py_False 是否相同
int Py_IsFalse(PyObject *x)
{
    return Py_Is(x, Py_False);
}

比较简单,相信对你来说已经没有任何难度了。

Image

None 的类型

说完了 None 本身,再来看看它的类型。

print(type(None))
"""
<class 'NoneType'>
"""

None 的类型是 NoneType,但这个类解释器没有暴露给我们,需要通过 type 去获取。

class MyNone(type(None)):
    pass
"""
TypeError: type 'NoneType' is not an acceptable base type
"""

注意:NoneType 无法被继承,当然我们一般也不会去继承它。

然后看一下 NoneType 的底层结构,它位于 Objects/object.c 中。

Image

NoneType 的类型也是 type,然后它实现了 tp_as_number。

// Objects/object.c
static PyNumberMethods none_as_number = {
    // ...
    (inquiry)none_bool,         /* nb_bool */
    // ...
};

但是只实现了里面的 nb_bool,用于生成布尔值。

// Objects/object.c
static int
none_bool(PyObject *v)
{
    return 0;
}

函数返回的是 0,因此调用 PyBool_FromLong 的时候,会返回 Py_False。

print(bool(None))  # False
print(not not None)  # False
Image

小结

以上我们就简单介绍了 None,当然内容有些过于简单了,因为 None 本身就没多少内容,核心就两点:

  • None 是单例的;