python中的数据对象主要包括以下几种

数据类型 类名 是否定长 底层C数据类型 .h文件
bool _Py_FalseStruct , _Py_TrueStruct 不定长 _longobject boolobject.h
int PyLongObject 不定长 uint32_t [] longobject.h
float PyFloatObject 定长 double floatobject.h
str PyBytesObject 不定长 char [] byteobject.h
tuple PyTupleObject 不定长 PyObject* [] tupleobject.h
list PyListObject 不定长 PyObject ** listobject.h
set PySetObject 不定长 PyObject ** setobject.h
dict PyDictObject 不定长 PyDictKeyObject * , PyObject ** dictobject.h

两个诡异的地方:

Python 3.7里,bool类型直接复用了PyLongObject,用0和1表示False和True。

在Python 3.7里,int值使用了Long类型的不定长变量,有别于Python 2.7的定长变量。在Python 3.7中,int不存在越界问题。

# Python 2中
#     int越界后自动扩展成long

In [1]: type(1)
Out[1]: int

In [2]: type(1<<65)
Out[2]: long

In [3]: 1<<65
Out[3]: 36893488147419103232L

# Python 3中
#     int的内部实现就是python 2的long
#     是C++的uint32_t数组,越界无感知
In [1]: type(1)
Out[1]: int

In [2]: type(1<<65)
Out[2]: int

In [3]: 1<<65
Out[3]: 36893488147419103232

由于这些诡异的更改,我们将先从定长的PyFloatObject看起,了解他们内部的机理。

一切的数据对象,都可以用PyObject指针调用的秘诀是什么?

PyFloatObject

使用PyObject一个指针就可以操控所有Object的秘诀在于,Python内部通过指针手动实现了多态。我们从PyFloatObject入手

/* File: cpython/Include/floatobject.h */
typedef struct {
    PyObject_HEAD
    double ob_fval;
} PyFloatObject;

其中 PyObject_HEAD的宏定义在 object.h中,他是一个叫ob_base的PyObject。

/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD                   PyObject ob_base;

也就是说,PyFloatObject是在PyObject的基础上,增加了ob_fval,而这个ob_fval就是一个double类型的变量,存储了float值。

如果我们用一个PyObject*指向PyFloatObject,并不会影响对头两个变量 ob_refcnt*ob_type的获取,而*ob_type保存了对象的类别信息,我们只需要借助PyObject*读取*ob_type中的的类别信息,就可以知道我们要把泛型指针PyObject*转换成哪种类型进行解析。

具体结构如下:

results matching ""

    No results matching ""