天天看點

1. Python3源碼—内建對象1.1. Python内的對象1.2. PyObject1.3. PyVarObject1.4. PyTypeObject1.5. Python對外提供的C API1.6 參考

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源碼剖析