日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python源码剖析_Python源码剖析 - 对象初探

發布時間:2023/12/10 python 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python源码剖析_Python源码剖析 - 对象初探 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

01 前言

對象是 python 中最核心的一個概念,在python的世界中,一切都是對象,整數、字符串、甚至類型、整數類型、字符串類型,都是對象。

02 什么是PyObject

Python 中凡事皆對象,而其中 PyObject 又是所有對象的基礎,它是 Python 對象機制的核心。因為它是基類,而其他對象都是對它的繼承。

打開 Include/python.h 中聲明如下:

#define PyObject_HEAD \

_PyObject_HEAD_EXTRA \

Py_ssize_t ob_refcnt; \

struct _typeobject *ob_type;

typedef struct _object {

PyObject_HEAD

} PyObject;

PyObject 有兩個重要的成員對象:

ob_refcnt - 表示引用計數,當有一個新的 PyObject * 引用該對象時候,則進行 +1 操作;同時,當這個 PyObject * 被刪除時,該引用計數就會減小。當計數為0時,該對象就會被回收,等待內存被釋放。

ob_type 記錄對象的類型信息,這個結構體含有很多信息,見如下代碼分析。

03 類型對象

在python中,預先定義了一些類型對象,比如 int 類型、str 類型、dict 類型等,這些我們稱之為內建類型對象,這些類型對象實現了面向對象中"類"的概念。

這些內建對象實例化之后,可以創建類型對象所對應的實例對象,比如 int 對象、str 對象、dict 對象。這些實例對象可以視為面向對象理論中的“對象"這個概念在python中的體現。

#define PyObject_VAR_HEAD \

PyObject_HEAD \

Py_ssize_t ob_size; /* Number of items in variable part */

typedef struct _typeobject {

PyObject_VAR_HEAD

const char *tp_name; /* For printing, in format "." */

Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

/* Methods to implement standard operations */

destructor tp_dealloc;

printfunc tp_print;

getattrfunc tp_getattr;

setattrfunc tp_setattr;

cmpfunc tp_compare;

reprfunc tp_repr;

/* Method suites for standard classes */

PyNumberMethods *tp_as_number;

PySequenceMethods *tp_as_sequence;

PyMappingMethods *tp_as_mapping;

/* Attribute descriptor and subclassing stuff */

struct PyMethodDef *tp_methods;

struct PyMemberDef *tp_members;

struct PyGetSetDef *tp_getset;

struct _typeobject *tp_base;

PyObject *tp_dict;

descrgetfunc tp_descr_get;

descrsetfunc tp_descr_set;

Py_ssize_t tp_dictoffset;

initproc tp_init;

allocfunc tp_alloc;

newfunc tp_new;

freefunc tp_free; /* Low-level free-memory routine */

inquiry tp_is_gc; /* For PyObject_IS_GC */

PyObject *tp_bases;

PyObject *tp_mro; /* method resolution order */

PyObject *tp_cache;

PyObject *tp_subclasses;

PyObject *tp_weaklist;

destructor tp_del;

...

} PyTypeObject;

這當中,我們需要關注幾個重點成員變量:

tp_name 即類型名稱,例如 'int', tuple', 'list'等,可以標準輸出

tp_basicsize 與 tp_itemsize, 創建該對象的內存信息

關聯操作

描述該類型的其他信息

04 定長對象與變長對象

定長對象比較好理解,例如一個整數對象,無論這個數值多大,它的存儲長度是一定的,這個長度由 _typeobject 來指定,不會變化。

typedef struct {

PyObject_HEAD

long ob_ival;

} PyIntObject;

變長對象在內存中的長度是不一定的,所以需要 ob_size 來記錄變長部分的個數,需要注意的是,這個并不是字節的數目。

#define PyObject_VAR_HEAD \

PyObject_HEAD \

Py_ssize_t ob_size; /* Number of items in variable part */

typedef struct {

PyObject_VAR_HEAD;

long ob_shash;

int ob_sstate;

char ob_sval[1];

/* Invariants:

* ob_sval contains space for 'ob_size+1' elements.

* ob_sval[ob_size] == 0.

* ob_shash is the hash of the string or -1 if not computed yet.

* ob_sstate != 0 iff the string object is in stringobject.c's

* 'interned' dictionary; in this case the two references

* from 'interned' to this object are *not counted* in ob_refcnt.

*/

} PyStringObject;

05 創建一個定長對象的例子

代碼如下:

a = int(10)

Python 主要做了以下操作:

第一步:分析需要創建的類型,如上,則是 PyInt_Type

第二步:根據 PyInt_Type 中的 int_new 函數來構造對象

第三步:識別上述代碼中的 10 為字符傳,然后調用 PyInt_FromString() 函數來構造

第四步:最后調用 PyInt_FromLong(long ival) 函數來進行整數對象的內存分配和賦值。

我們先看一下 PyInt_Type的代碼實現:

tp_name 被賦值為“int”,這樣在 type() 函數時,就會顯示該字符串

指定 “int” 類的關聯操作,如釋放、打印、比較等

tp_basicsize 賦值為 sizeof(PyIntObject)

tp_itemsize 賦值為 0

PyTypeObject PyInt_Type = {

PyVarObject_HEAD_INIT(&PyType_Type, 0)

"int",

sizeof(PyIntObject),

0,

(destructor)int_dealloc, /* tp_dealloc */

(printfunc)int_print, /* tp_print */

0, /* tp_getattr */

0, /* tp_setattr */

(cmpfunc)int_compare, /* tp_compare */

(reprfunc)int_to_decimal_string, /* tp_repr */

&int_as_number, /* tp_as_number */

0, /* tp_as_sequence */

0, /* tp_as_mapping */

(hashfunc)int_hash, /* tp_hash */

0, /* tp_call */

(reprfunc)int_to_decimal_string, /* tp_str */

PyObject_GenericGetAttr, /* tp_getattro */

0, /* tp_setattro */

0, /* tp_as_buffer */

Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |

Py_TPFLAGS_BASETYPE | Py_TPFLAGS_INT_SUBCLASS, /* tp_flags */

int_doc, /* tp_doc */

0, /* tp_traverse */

0, /* tp_clear */

0, /* tp_richcompare */

0, /* tp_weaklistoffset */

0, /* tp_iter */

0, /* tp_iternext */

int_methods, /* tp_methods */

0, /* tp_members */

int_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 */

int_new, /* tp_new */

};

這里我們對 int_new 方法進行展開, int_new 方法就是創建函數,類似于 C++ 中的構造函數,用來生成PyIntObject 代碼如下:

static PyObject *

int_new(PyTypeObject *type, PyObject *args, PyObject *kwds)

{

PyObject *x = NULL;

int base = -909;

static char *kwlist[] = {"x", "base", 0};

if (type != &PyInt_Type)

return int_subtype_new(type, args, kwds); /* Wimp out */

if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:int", kwlist,

&x, &base))

return NULL;

if (x == NULL) {

if (base != -909) {

PyErr_SetString(PyExc_TypeError,

"int() missing string argument");

return NULL;

}

return PyInt_FromLong(0L);

}

if (base == -909)

return PyNumber_Int(x);

if (PyString_Check(x)) {

/* Since PyInt_FromString doesn't have a length parameter,

* check here for possible NULs in the string. */

char *string = PyString_AS_STRING(x);

if (strlen(string) != PyString_Size(x)) {

/* create a repr() of the input string,

* just like PyInt_FromString does */

PyObject *srepr;

srepr = PyObject_Repr(x);

if (srepr == NULL)

return NULL;

PyErr_Format(PyExc_ValueError,

"invalid literal for int() with base %d: %s",

base, PyString_AS_STRING(srepr));

Py_DECREF(srepr);

return NULL;

}

return PyInt_FromString(string, NULL, base);

}

#ifdef Py_USING_UNICODE

if (PyUnicode_Check(x))

return PyInt_FromUnicode(PyUnicode_AS_UNICODE(x),

PyUnicode_GET_SIZE(x),

base);

#endif

PyErr_SetString(PyExc_TypeError,

"int() can't convert non-string with explicit base");

return NULL;

}

最后通過 PyInt_FromLong 方法對新產生的對象的type信息就行賦值為 PyInt_Type,并設置整數的具體數值。其中如果是小整數,則可以從 small_ints 數組中直接放回。

#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject))

#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */

#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */

static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

struct _intblock {

struct _intblock *next;

PyIntObject objects[N_INTOBJECTS];

};

typedef struct _intblock PyIntBlock;

static PyIntBlock *block_list = NULL;

static PyIntObject *free_list = NULL;

PyObject *

PyInt_FromLong(long ival)

{

register PyIntObject *v;

#if NSMALLNEGINTS + NSMALLPOSINTS > 0

if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {

v = small_ints[ival + NSMALLNEGINTS];

Py_INCREF(v);

#ifdef COUNT_ALLOCS

if (ival >= 0)

quick_int_allocs++;

else

quick_neg_int_allocs++;

#endif

return (PyObject *) v;

}

#endif

if (free_list == NULL) {

if ((free_list = fill_free_list()) == NULL)

return NULL;

}

/* Inline PyObject_New */

v = free_list;

free_list = (PyIntObject *)Py_TYPE(v);

(void)PyObject_INIT(v, &PyInt_Type);

v->ob_ival = ival;

return (PyObject *) v;

}

06 展開

為了性能考慮,python 中對小整數有專門的緩存池,這樣就不需要每次使用小整數對象時去用 malloc 分配內存以及free釋放內存。

小整數之外的大整數怎么避免重復分配和回收內存呢?

Python 的方案是 PyIntBlock。PyIntBlock 這個結構就是一塊內存,里面保存 PyIntObject 對象。一個 PyIntBlock 默認存放 N_INTOBJECTS 對象。

PyIntBlock 鏈表通過 block_list 維護,每個block中都維護一個 PyIntObject 數組 objects,block 的 objects 可能會有些內存空閑,因此需要另外用一個 free_list 鏈表串起來這些空閑的項以方便再次使用。objects 數組中的 PyIntObject 對象通過 ob_type 字段從后往前鏈接。

小整數的緩存池最終實現也是生存在 block_list 維護的內存上,在 python 初始化時,會調用 PyInt_Init 函數申請內存并創建小整數對象。

更多內容

如果你對Python語言感興趣,可以關注我,或者關注我的微信公眾號:xtuz666

總結

以上是生活随笔為你收集整理的python源码剖析_Python源码剖析 - 对象初探的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。