楔子
本篇文章来聊一聊 None 是怎么实现的,None 在 Python 里面也是一个对象,用于表示空(值不存在的情况)。比如基于主键从数据库获取记录,如果没有查询到,那么一般会返回 None。
另外如果函数没有返回值,那么会隐式地返回 None,表示返回的是空。
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);
}
比较简单,相信对你来说已经没有任何难度了。
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 中。
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
小结
以上我们就简单介绍了 None,当然内容有些过于简单了,因为 None 本身就没多少内容,核心就两点: