1. Python3源码—内建对象

简介: # 1.1. Python内的对象 Python中的类和实例都是通过Python内的对象来实现的。Python中已经预先定义了一些类型对象。这些内建类型对象通过实例化,可以创建内建类型对象的实例对象。 在Python中,对象就是为C中的结构体在堆上申请的一块内存,一般来说,对象是不能被静态初始化的,并且也不能在栈空间上生存。唯一的例外就是类型对象,Python中所有的内建的类型对象都是被静

1.1. Python内的对象

Python中的类和实例都是通过Python内的对象来实现的。Python中已经预先定义了一些类型对象。这些内建类型对象通过实例化,可以创建内建类型对象的实例对象。

在Python中,对象就是为C中的结构体在堆上申请的一块内存,一般来说,对象是不能被静态初始化的,并且也不能在栈空间上生存。唯一的例外就是类型对象,Python中所有的内建的类型对象都是被静态初始化的。

在Python中,一个对象一旦被创建,它在内存中的大小就是不变的了。这就意味着那些需要容纳可变长度数据的对象只能在对象内维护一个指向一块可变大小的内存区域的指针。

1.2. PyObject

PyObject是整个Python对象机制的核心,定义如下:

// object.h
typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

其中_PyObject_HEAD_EXTRA定义如下:

// object.h
#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;

#define _PyObject_EXTRA_INIT 0, 0,

#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif

可以看到release编译时不会定义Py_TRACE_REFS。

PyObject类中ob_refcnt与内存引用计数相关,ob_type用来指定一个对象类型的类型对象。在Python中,对象机制的核心一个是引用计数,一个就是类型信息。

每一个Python对象除了必须有这个PyObject内容外,还应该占有一些额外的内存,放置些其他的东西。比如float对象除了PyObject,还有一个额外的double变量,如下定义:

// floatobject.h
typedef struct {
    PyObject_HEAD
    double ob_fval;
} PyFloatObject;

其中PyObject_HEAD定义了PyObject类型对象,如下:

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

1.3. PyVarObject

把浮点对象这样不包含可变长度数据的对象称为“定长对象”,而字符串对象这样包含可变长度数据的对象称为“变长对象”,它们的区别在于定长对象的不同对象占用的内存大小是一样的,而变长对象的不同对象占用的内存可能是不一样的。

表示变长对象的结构体PyVarObject定义如下:

// object.h
typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

每一个可变Python对象除了有PyVarObject内容外,还占有一些额外的内存,放置些其他的东西。比如list对象为变长对象,它的结构体如下:

// listobject.h
typedef struct {
    PyObject_VAR_HEAD
    PyObject **ob_item;
    Py_ssize_t allocated;
} PyListObject;

其中PyObject_VAR_HEAD定义了PyVarObject类型对象,如下:

// object.h
/* PyObject_VAR_HEAD defines the initial segment of all variable-size container objects. */
#define PyObject_VAR_HEAD     PyVarObject ob_base;

1.4. PyTypeObject

对象对应的类型对象定义如下:

// object.h
typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; 

    Py_ssize_t tp_basicsize, tp_itemsize;

    /* Methods to implement standard operations */
    destructor tp_dealloc;
    printfunc tp_print;
    
       // ...
} PyTypeObject;

定义中包含了许多信息,主要分为4类:

  • 类型名,tp_name,主要是Python内部以及调试的时候使用;
  • 创建该类型对象时分配内存空间大小的信息,即tp_basicsize和tp_itemsize;
  • 与该类型对象相关联的操作信息,诸如tp_print这样的函数;
  • 类型的类型信息;

在PyTypeObject中定义了大量的函数指针,这些函数指针最终都会指向某个函数,或者指向NULL,可以视为类型对象中所定义的操作。在这些操作信息中,有三组非常重要的操作族:tp_as_number,tp_as_sequence和tp_as_mapping,分别指向PyNumberMethods,PySequenceMethods和PyMappingMethods函数族。PyNumberMethods、PySequenceMethods、PyMappingMethods分别定义了作为一个数值对象、序列对象和关联对象应该支持的操作。

类型对象的类型是PyType_Type:

PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                            /* tp_name */
    sizeof(PyHeapTypeObject),          /* tp_basicsize */
    sizeof(PyMemberDef),               /* tp_itemsize */
    (destructor)type_dealloc,          /* tp_dealloc */
    0,                                 /* tp_print */
    0,                                 /* tp_getattr */
    0,                                 /* tp_setattr */
    0,                                 /* tp_reserved */
    (reprfunc)type_repr,               /* tp_repr */
    0,                                 /* tp_as_number */
    0,                                 /* tp_as_sequence */
    0,                                 /* tp_as_mapping */
    0,                                 /* tp_hash */
    (ternaryfunc)type_call,            /* tp_call */
    0,                                 /* tp_str */
    (getattrofunc)type_getattro,       /* tp_getattro */
    (setattrofunc)type_setattro,       /* tp_setattro */
    0,                                 /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS,                                                   /* tp_flags */
    type_doc,                          /* tp_doc */
    (traverseproc)type_traverse,       /* tp_traverse */
    (inquiry)type_clear,               /* tp_clear */
    0,                                 /* tp_richcompare */
    offsetof(PyTypeObject, tp_weaklist),  /* tp_weaklistoffset */
    0,                                  /* tp_iter */
    0,                                  /* tp_iternext */
    type_methods,                       /* tp_methods */
    type_members,                       /* tp_members */
    type_getsets,                       /* tp_getset */
    0,                                  /* tp_base */
    0,                                  /* tp_dict */
    0,                                  /* tp_descr_get */
    0,                                  /* tp_descr_set */
    offsetof(PyTypeObject, tp_dict),    /* tp_dictoffset */
    type_init,                          /* tp_init */
    0,                                  /* tp_alloc */
    type_new,                           /* tp_new */
    PyObject_GC_Del,                    /* tp_free */
    (inquiry)type_is_gc,                /* tp_is_gc */
};

1.5. Python对外提供的C API

Python的C API分为两类,一类称为范性的API(AOL,Abstract Object Layer),这类API都具有诸如PyObject_*的形式,可以应用在任何Python对象上;另一类是与类型相关的API(COL,Concrete Object Layer),这类API通常只能作用在某一种类型的对象上,对于每一种内建对象,Python都提供了这样的一组API。

1.6 参考

  • Python源码剖析
目录
相关文章
|
2月前
|
Python
用python进行视频剪辑源码
这篇文章提供了一个使用Python进行视频剪辑的源码示例,通过结合moviepy和pydub库来实现视频的区间切割和音频合并。
64 2
|
1月前
|
存储 缓存 Java
深度解密 Python 虚拟机的执行环境:栈帧对象
深度解密 Python 虚拟机的执行环境:栈帧对象
62 13
|
1月前
|
索引 Python
Python 对象的行为是怎么区分的?
Python 对象的行为是怎么区分的?
26 3
|
1月前
|
存储 缓存 算法
详解 PyTypeObject,Python 类型对象的载体
详解 PyTypeObject,Python 类型对象的载体
34 3
|
1月前
|
Python
深入解析 Python 中的对象创建与初始化:__new__ 与 __init__ 方法
深入解析 Python 中的对象创建与初始化:__new__ 与 __init__ 方法
19 1
|
1月前
|
缓存 Java 程序员
一个 Python 对象会在何时被销毁?
一个 Python 对象会在何时被销毁?
39 2
|
1月前
|
API Python 容器
再探泛型 API,感受 Python 对象的设计哲学
再探泛型 API,感受 Python 对象的设计哲学
20 2
|
1月前
|
API Python
当调用一个 Python 对象时,背后都经历了哪些过程?
当调用一个 Python 对象时,背后都经历了哪些过程?
22 2
|
1月前
|
存储 API C语言
当创建一个 Python 对象时,背后都经历了哪些过程?
当创建一个 Python 对象时,背后都经历了哪些过程?
19 2
|
1月前
|
存储 C语言 Python
解密 Python 的变量和对象,它们之间有什么区别和联系呢?
解密 Python 的变量和对象,它们之间有什么区别和联系呢?
23 2