楔子

None 在 Python 里面也是一个对象,用于表示空(值不存在的情况)。比如基于主键从数据库获取记录,如果没有查询到,那么一般会返回 None。另外如果函数没有返回值,那么也会隐式地返回 None,表示返回的是空。

本篇文章就来聊一聊 None 是怎么实现的。

None 的底层结构

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

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

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

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

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

None 的类型

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

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

None 的类型是 <class 'NoneType'>,但这个类解释器没有暴露给我们,需要通过 type 去获取。注意:NoneType 无法被继承,当然我们一般也不会去继承它。

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

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

PyTypeObject _PyNone_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "NoneType",
    0,
    0,
    none_dealloc,       /*tp_dealloc*/ /*never called*/
    0,                  /*tp_vectorcall_offset*/
    0,                  /*tp_getattr*/
    0,                  /*tp_setattr*/
    0,                  /*tp_as_async*/
    none_repr,          /*tp_repr*/
    &none_as_number,    /*tp_as_number*/
    0,                  /*tp_as_sequence*/
    0,                  /*tp_as_mapping*/
    0,                  /*tp_hash */
    0,                  /*tp_call */
    0,                  /*tp_str */
    0,                  /*tp_getattro */
    0,                  /*tp_setattro */
    0,                  /*tp_as_buffer */
    Py_TPFLAGS_DEFAULT, /*tp_flags */
    0,                  /*tp_doc */
    0,                  /*tp_traverse */
    0,                  /*tp_clear */
    0,                  /*tp_richcompare */
    0,                  /*tp_weaklistoffset */
    0,                  /*tp_iter */
    0,                  /*tp_iternext */
    0,                  /*tp_methods */
    0,                  /*tp_members */
    0,                  /*tp_getset */
    0,                  /*tp_base */
    0,                  /*tp_dict */
    0,                  /*tp_descr_get */
    0,                  /*tp_descr_set */
    0,                  /*tp_dictoffset */
    0,                  /*tp_init */
    0,                  /*tp_alloc */
    none_new,           /*tp_new */
};

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 本身就没多少内容,核心就两点:

  • None 是单例的;
  • 判断的时候使用 is 关键字;

 

欢迎大家关注我的公众号:古明地觉的编程教室。

如果觉得文章对你有所帮助,也可以请作者吃个馒头,Thanks♪(・ω・)ノ。