最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python列表對(duì)象實(shí)現(xiàn)原理詳解

 更新時(shí)間:2019年07月01日 10:15:25   作者:FOOFISH-PYTHON之禪  
這篇文章主要介紹了Python列表對(duì)象實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

Python中的列表基于PyListObject實(shí)現(xiàn),列表支持元素的插入、刪除、更新操作,因此PyListObject是一個(gè)變長(zhǎng)對(duì)象(列表的長(zhǎng)度隨著元素的增加和刪除而變長(zhǎng)和變短),同時(shí)它還是一個(gè)可變對(duì)象(列表中的元素根據(jù)列表的操作而發(fā)生變化,內(nèi)存大小動(dòng)態(tài)的變化),PyListObject的定義:

typedef struct {
# 列表對(duì)象引用計(jì)數(shù)
int ob_refcnt; 
# 列表類(lèi)型對(duì)象 
struct _typeobject *ob_type;
# 列表元素的長(zhǎng)度
int ob_size; /* Number of items in variable part */
# 真正存放列表元素容器的指針,list[0] 就是 ob_item[0]
PyObject **ob_item;
# 當(dāng)前列表可容納的元素大小
Py_ssize_t allocated;
} PyListObject;

咋一看PyListObject對(duì)象的定義非常簡(jiǎn)單,除了通用對(duì)象都有的引用計(jì)數(shù)(ob_refcnt)、類(lèi)型信息(ob_type),以及變長(zhǎng)對(duì)象的長(zhǎng)度(ob_size)之外,剩下的只有ob_item,和allocated,ob_item是真正存放列表元素容器的指針,專(zhuān)門(mén)有一塊內(nèi)存用來(lái)存儲(chǔ)列表元素,這塊內(nèi)存的大小就是allocated所能容納的空間。alloocated是列表所能容納的元素大小,而且滿足條件:

  • 0 <= ob_size <= allocated
  • len(list) == ob_size
  • ob_item == NULL 時(shí) ob_size == allocated == 0

列表對(duì)象的創(chuàng)建

PylistObject對(duì)象的是通過(guò)函數(shù)PyList_New創(chuàng)建而成,接收參數(shù)size,該參數(shù)用于指定列表對(duì)象所能容納的最大元素個(gè)數(shù)。

// 列表緩沖池, PyList_MAXFREELIST為80
static PyListObject *free_list[PyList_MAXFREELIST];
//緩沖池當(dāng)前大小
static int numfree = 0;
PyObject *PyList_New(Py_ssize_t size)
{
PyListObject *op; //列表對(duì)象
size_t nbytes; //創(chuàng)建列表對(duì)象需要分配的內(nèi)存大小
if (size < 0) {
PyErr_BadInternalCall();
return NULL;
}
/* Check for overflow without an actual overflow,
* which can cause compiler to optimise out */
if ((size_t)size > PY_SIZE_MAX / sizeof(PyObject *))
return PyErr_NoMemory();
nbytes = size * sizeof(PyObject *);
if (numfree) {
numfree--;
op = free_list[numfree];
_Py_NewReference((PyObject *)op);
} else {
op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL)
return NULL;
}
if (size <= 0)
op->ob_item = NULL;
else {
op->ob_item = (PyObject **) PyMem_MALLOC(nbytes);
if (op->ob_item == NULL) {
Py_DECREF(op);
return PyErr_NoMemory();
}
memset(op->ob_item, 0, nbytes);
}
# 設(shè)置ob_size
Py_SIZE(op) = size;
op->allocated = size;
_PyObject_GC_TRACK(op);
return (PyObject *) op;
}

創(chuàng)建過(guò)程大致是:

  1. 檢查size參數(shù)是否有效,如果小于0,直接返回NULL,創(chuàng)建失敗
  2. 檢查size參數(shù)是否超出Python所能接受的大小,如果大于PY_SIZE_MAX(64位機(jī)器為8字節(jié),在32位機(jī)器為4字節(jié)),內(nèi)存溢出。
  3. 檢查緩沖池free_list是否有可用的對(duì)象,有則直接從緩沖池中使用,沒(méi)有則創(chuàng)建新的PyListObject,分配內(nèi)存。
  4. 初始化ob_item中的元素的值為Null
  5. 設(shè)置PyListObject的allocated和ob_size。

PYLISTOBJECT對(duì)象的緩沖池

free_list是PyListObject對(duì)象的緩沖池,其大小為80,那么PyListObject對(duì)象是什么時(shí)候加入到緩沖池free_list的呢?答案在list_dealloc方法中:

static void
list_dealloc(PyListObject *op)
{
Py_ssize_t i;
PyObject_GC_UnTrack(op);
Py_TRASHCAN_SAFE_BEGIN(op)
if (
i = Py_SIZE(op);
while (--i >= 0) {
Py_XDECREF(op->ob_item[i]);
}
PyMem_FREE(op->ob_item);
}
if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
free_list[numfree++] = op;
else
Py_TYPE(op)->tp_free((PyObject *)op);
Py_TRASHCAN_SAFE_END(op)
}

當(dāng)PyListObject對(duì)象被銷(xiāo)毀的時(shí)候,首先將列表中所有元素的引用計(jì)數(shù)減一,然后釋放ob_item占用的內(nèi)存,只要緩沖池空間還沒(méi)滿,那么就把該P(yáng)yListObject加入到緩沖池中(此時(shí)PyListObject占用的內(nèi)存并不會(huì)正真正回收給系統(tǒng),下次創(chuàng)建PyListObject優(yōu)先從緩沖池中獲取PyListObject),否則釋放PyListObject對(duì)象的內(nèi)存空間。

列表元素插入

設(shè)置列表某個(gè)位置的值時(shí),如“l(fā)ist[1]=0”,列表的內(nèi)存結(jié)構(gòu)并不會(huì)發(fā)生變化,而往列表中插入元素時(shí)會(huì)改變列表的內(nèi)存結(jié)構(gòu):

static int
ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
{
// n是列表元素長(zhǎng)度
Py_ssize_t i, n = Py_SIZE(self);
PyObject **items;
if (v == NULL) {
PyErr_BadInternalCall();
return -1;
}
if (n == PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"cannot add more objects to list");
return -1;
}
if (list_resize(self, n+1) == -1)
return -1;
if (where < 0) {
where += n;
if (where < 0)
where = 0;
}
if (where > n)
where = n;
items = self->ob_item;
for (i = n; --i >= where; )
items[i+1] = items[i];
Py_INCREF(v);
items[where] = v;
return 0;
}

相比設(shè)置某個(gè)列表位置的值來(lái)說(shuō),插入操作要多一次PyListObject容量大小的調(diào)整,邏輯是list_resize,其次是挪動(dòng)where之后的元素位置。

// newsize: 列表新的長(zhǎng)度
static int 
list_resize(PyListObject *self, Py_ssize_t newsize)
{
PyObject **items;
size_t new_allocated;
Py_ssize_t allocated = self->allocated;
if (allocated >= newsize && newsize >= (allocated >> 1)) {
assert(self->ob_item != NULL || newsize == 0);
Py_SIZE(self) = newsize;
return 0;
}
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
/* check for integer overflow */
if (new_allocated > PY_SIZE_MAX - newsize) {
PyErr_NoMemory();
return -1;
} else {
new_allocated += newsize;
}
if (newsize == 0)
new_allocated = 0;
items = self->ob_item;
if (new_allocated <= (PY_SIZE_MAX / sizeof(PyObject *)))
PyMem_RESIZE(items, PyObject *, new_allocated);
else
items = NULL;
if (items == NULL) {
PyErr_NoMemory();
return -1;
}
self->ob_item = items;
Py_SIZE(self) = newsize;
self->allocated = new_allocated;
return 0;
}

滿足 allocated >= newsize && newsize >= (allocated /2)時(shí),簡(jiǎn)單改變list的元素長(zhǎng)度,PyListObject對(duì)象不會(huì)重新分配內(nèi)存空間,否則重新分配內(nèi)存空間,如果newsize<allocated/2,那么會(huì)減縮內(nèi)存空間,如果newsize>allocated,就會(huì)擴(kuò)大內(nèi)存空間。當(dāng)newsize==0時(shí)內(nèi)存空間將縮減為0。

總結(jié)

  • PyListObject緩沖池的創(chuàng)建發(fā)生在列表銷(xiāo)毀的時(shí)候。
  • PyListObject對(duì)象的創(chuàng)建分兩步:先創(chuàng)建PyListObject對(duì)象,然后初始化元素列表為NULL。
  • PyListObject對(duì)象的銷(xiāo)毀分兩步:先銷(xiāo)毀PyListObject對(duì)象中的元素列表,然后銷(xiāo)毀PyListObject本身。
  • PyListObject對(duì)象內(nèi)存的占用空間會(huì)根據(jù)列表長(zhǎng)度的變化而調(diào)整。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • python?數(shù)據(jù)保存為npy和npz格式并讀取的完整代碼

    python?數(shù)據(jù)保存為npy和npz格式并讀取的完整代碼

    這篇文章主要介紹了python?數(shù)據(jù)保存為npy和npz格式并讀取,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • 代碼詳解Python的函數(shù)基礎(chǔ)(2)

    代碼詳解Python的函數(shù)基礎(chǔ)(2)

    這篇文章主要為大家詳細(xì)介紹了Python的函數(shù)基礎(chǔ),使用了函數(shù)參數(shù)和遞歸函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • python求numpy中array按列非零元素的平均值案例

    python求numpy中array按列非零元素的平均值案例

    這篇文章主要介紹了python求numpy中array按列非零元素的平均值案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-06-06
  • python讀取Excel實(shí)例詳解

    python讀取Excel實(shí)例詳解

    這篇文章主要為大家詳細(xì)介紹了python讀取Excel的實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • python使用mailbox打印電子郵件的方法

    python使用mailbox打印電子郵件的方法

    這篇文章主要介紹了python使用mailbox打印電子郵件的方法,涉及Python打印電子郵件的相關(guān)技巧,需要的朋友可以參考下
    2015-04-04
  • python神經(jīng)網(wǎng)絡(luò)slim常用函數(shù)訓(xùn)練保存模型

    python神經(jīng)網(wǎng)絡(luò)slim常用函數(shù)訓(xùn)練保存模型

    這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)使用slim函數(shù)進(jìn)行模型的訓(xùn)練及保存模型示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • python實(shí)現(xiàn)簡(jiǎn)易學(xué)生信息管理系統(tǒng)

    python實(shí)現(xiàn)簡(jiǎn)易學(xué)生信息管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡(jiǎn)易學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • 詳談Python2.6和Python3.0中對(duì)除法操作的異同

    詳談Python2.6和Python3.0中對(duì)除法操作的異同

    下面小編就為大家?guī)?lái)一篇詳談Python2.6和Python3.0中對(duì)除法操作的異同。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04
  • 淺談pytorch torch.backends.cudnn設(shè)置作用

    淺談pytorch torch.backends.cudnn設(shè)置作用

    今天小編就為大家分享一篇淺談pytorch torch.backends.cudnn設(shè)置作用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-02-02
  • Python對(duì)excel文檔的操作方法詳解

    Python對(duì)excel文檔的操作方法詳解

    這篇文章主要介紹了Python對(duì)excel文檔的操作方法,結(jié)合實(shí)例形式分析了Python基于xlrd、xlwd庫(kù)針對(duì)Excel文件的讀寫(xiě)、sheet表創(chuàng)建、獲取、遍歷等相關(guān)操作技巧,需要的朋友可以參考下
    2018-12-12

最新評(píng)論

科技| 美姑县| 白山市| 家居| 昭通市| 丽水市| 东乌珠穆沁旗| 思南县| 台州市| 和平区| 六安市| 泸西县| 江山市| 老河口市| 诸城市| 北碚区| 霍山县| 资溪县| 岫岩| 汉寿县| 共和县| 贡山| 广昌县| 黄冈市| 阳泉市| 屯留县| 棋牌| 肇州县| 辽中县| 兰坪| 藁城市| 治多县| 贵州省| 双桥区| 沙洋县| 武宁县| 沂源县| 东丰县| 寻甸| 合川市| 武安市|