1.1.1 PyLongObject对象
Python中对整数这个概念的实现是通过PyLongObject对象来完成的。
第0章讲解了定长对象和变长对象的区别,这是一种关于对象的二分法。实际上还存在另一种关于对象的二分法,即根据对象维护数据时的可变性将对象分为可变对象(Mutable)和不可变对象(Immutable)。
这里将要剖析的PyLongObject对象是一个不可变对象,这种不变性是针对PyLong-Object对象中所维护的真实的整数值而言的。也就是说,在创建了PyLongObject对象之后,就再也不能改变该对象的值了。在Python中,除PyLongObject之外,还有很多对象是不可变对象,比如字符串对象等。
在Python的应用程序中,整数的使用非常广泛,创建和删除操作非常频繁,并且结合了引用计数机制,这意味着系统堆将面临着整数对象大量的访问,这样的执行效率可以接受吗?因此设计一个高效的运行时机制,使得整数对象的使用不会成为Python的瓶颈,就成了一个至关重要的设计决策。
整数对象池是解决这个问题的一个非常好的办法。面向特定对象的缓冲池机制是Python语言实现时的核心设计策略之一。在Python中,几乎所有的内置对象都会有自己所特有的对象缓冲池机制。
PyLongObject对象的源码位置为Include/longobject.h及Include/longintrepr.h。
实际上,Python中的整数对象PyLongObject是对C中原生类型long的简单包装。Python中的对象与对象相关的元信息都保存在与对象对应的类型对象中。PyLongObject的类型对象是PyLong_Type。
PyLong_Type的源码位置为Objects/longobject.c,源码如下:
PyTypeObject PyLong_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "int", /* tp_name */ offsetof(PyLongObject, ob_digit), /* tp_basicsize */ sizeof(digit), /* tp_itemsize */ 0, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ long_to_decimal_string, /* tp_repr */ &long_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ (hashfunc)long_hash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */ long_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ long_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ long_methods, /* tp_methods */ 0, /* tp_members */ long_getset, /* 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 */ long_new, /* tp_new */ PyObject_Del, /* tp_free */ };
PyLong_Type中保存了关于PyLongObject对象的丰富元信息,包括PyLongObject对象应该占用的内存大小,PyLongObject对象的文档信息,PyLongObject对象所支持的操作。
从PyLong_Type的源码中可以看到,创建整数对象的入口函数为long_new。该入口函数的源码位置为Objects/clinic/longobject.c.h。具体实现函数为long_new_impl,源码位置为Objects/longobject.c。