Python帶你從淺入深探究Tuple(基礎(chǔ)篇)
Python中的元組容器序列(tuple)與列表容器序列(list)具有極大的相似之處,因此也常被稱為不可變的列表。
但是兩者之間也有很多的差距,元組側(cè)重于數(shù)據(jù)的展示,而列表側(cè)重于數(shù)據(jù)的存儲與操作。
它們非常相似,雖然都可以存儲任意類型的數(shù)據(jù),但是一個元組定義好之后就不能夠再進(jìn)行修改。
元組特性元組的特點:
元組屬于容器序列 元組屬于不可變類型 元組底層由順序存儲組成,而順序存儲是線性結(jié)構(gòu)的一種基本聲明
以下是使用類實例化的形式進(jìn)行對象聲明:
tup = tuple((1, 2, 3, 4, 5))print('值:%r,類型:%r' % (tup, type(tup)))# 值:(1, 2, 3, 4, 5),類型:<class ’tuple’>
也可以選擇使用更方便的字面量形式進(jìn)行對象聲明,使用逗號對數(shù)據(jù)項之間進(jìn)行分割:
tup = 1, 2, 3, 4, 5print('值:%r,類型:%r' % (tup, type(tup)))# 值:(1, 2, 3, 4, 5),類型:<class ’tuple’>
為了美觀,我們一般會在兩側(cè)加上(),但是要確定一點,元組定義是逗號分隔的數(shù)據(jù)項,而并非是()包裹的數(shù)據(jù)項:
tup = (1, 2, 3, 4, 5)print('值:%r,類型:%r' % (tup, type(tup)))# 值:(1, 2, 3, 4, 5),類型:<class ’tuple’>多維元組
當(dāng)一個元組中嵌套另一個元組,該元組就可以稱為多維元組。
如下,定義一個2維元組:
tup = (1, 2, 3, 4, 5)print('值:%r,類型:%r' % (tup, type(tup)))# 值:(1, 2, 3, 4, 5),類型:<class ’tuple’>續(xù)行操作
在Python中,元組中的數(shù)據(jù)項如果過多,可能會導(dǎo)致整個元組太長,太長的元組是不符合PEP8規(guī)范的。
每行最大的字符數(shù)不可超過79,文檔字符或者注釋每行不可超過72
Python雖然提供了續(xù)行符,但是在元組中可以忽略續(xù)行符,如下所示:
tup = (1, 2, ('三', '四'))print('值:%r,類型:%r' % (tup, type(tup)))# 值:(1, 2, (’三’, ’四’)),類型:<class ’tuple’>類型轉(zhuǎn)換
元組支持與布爾型、字符串、列表、以及集合類型進(jìn)行類型轉(zhuǎn)換:
tup = (1, 2, 3)bTup = bool(tup) # 布爾類型strTup = str(tup) # 字符串類型liTup = list(tup) # 列表類型setTup = set(tup) # 集合類型print('值:%r,類型:%r' % (bTup, type(bTup)))print('值:%r,類型:%r' % (strTup, type(strTup)))print('值:%r,類型:%r' % (liTup, type(liTup)))print('值:%r,類型:%r' % (setTup, type(setTup)))# 值:True,類型:<class ’bool’># 值:’(1, 2, 3)’,類型:<class ’str’># 值:[1, 2, 3],類型:<class ’list’># 值:{1, 2, 3},類型:<class ’set’>
如果一個2維元組遵循一定的規(guī)律,那么也可以將其轉(zhuǎn)換為字典類型:
tup = (('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3'))dictTuple = dict(tup)print('值:%r,類型:%r' % (dictTuple, type(dictTuple)))# 值:{’k1’: ’v1’, ’k2’: ’v2’, ’k3’: ’v3’},類型:<class ’dict’>索引操作
元組的索引操作僅支持獲取數(shù)據(jù)項。
其他的任意索引操作均不被支持。
使用方法參照列表的索引切片一節(jié)。
絕對引用元組擁有絕對引用的特性,無論是深拷貝還是淺拷貝,都不會獲得其副本,而是直接對源對象進(jìn)行引用。
但是列表沒有絕對引用的特性,代碼驗證如下:
>>> import copy>>> # 列表的深淺拷貝均創(chuàng)建新列表...>>> oldLi = [1, 2, 3]>>> id(oldLi)4542649096>>> li1 = copy.copy(oldLi)>>> id(li1)4542648840>>> li2 = copy.deepcopy(oldLi)>>> id(li2)4542651208>>> # 元組的深淺拷貝始終引用老元組>>> oldTup = (1, 2, 3)>>> id(oldTup)4542652920>>> tup1 = copy.copy(oldTup)>>> id(tup1)4542652920>>> tup2 = copy.deepcopy(oldTup)>>> id(tup2)4542652920
Python為何要這樣設(shè)計?其實仔細(xì)想想不難發(fā)現(xiàn),元組不能對其進(jìn)行操作,僅能獲取數(shù)據(jù)項。
那么也就沒有生成多個副本提供給開發(fā)人員操作的必要了,因為你修改不了元組,索性直接使用絕對引用策略。
值得注意的一點:[:]也是淺拷貝,故對元組來說屬于絕對引用范疇。
元組的陷阱Leonardo Rochael在2013年的Python巴西會議提出了一個非常具有思考意義的問題。
我們先來看一下:
>>> t = (1, 2, [30, 40])>>> t[-1] += [50, 60]Traceback (most recent call last): File '<stdin>', line 1, in <module>TypeError: ’tuple’ object does not support item assignment
現(xiàn)在,t到底會發(fā)生下面4種情況中的哪一種?
t 變成 (1, 2, [30, 40, 50, 60])。 因為 tuple 不支持對它的數(shù)據(jù)項賦值,所以會拋出 TypeError 異常。 以上兩個都不是。a 和 b 都是對的。正確答案是4,t確實會變成 (1, 2, [30, 40, 50, 60]),但同時元組是不可變類型故會引發(fā)TypeError異常的出現(xiàn)。
>>> t(1, 2, [30, 40, 50, 60])
如果是使用extend()對t[-1]的列表進(jìn)行數(shù)據(jù)項的增加,則答案會變成1。
我當(dāng)初在看了這個問題后,暗自告訴自己了2件事情:
list的數(shù)據(jù)項增加盡量不要使用+=,而應(yīng)該使用append()或者extend()Ps:我也不知道自己為什么會產(chǎn)生這樣的想法,但這個想法確實伴隨我很長時間,直至現(xiàn)在
tuple中不要存放可變類型的數(shù)據(jù),如list、set、dict等..元組更多的作用是展示數(shù)據(jù),而不是操作數(shù)據(jù)。
舉個例子,當(dāng)用戶根據(jù)某個操作獲取到了眾多數(shù)據(jù)項之后,你可以將這些數(shù)據(jù)項做出元組并返回。
用戶對被返回的原對象只能看,不能修改,若想修改則必須創(chuàng)建新其他類型對象。
解構(gòu)方法元組的解構(gòu)方法與列表使用相同。
使用方法參照列表的解構(gòu)方法一節(jié)。
常用方法方法一覽
常用的list方法一覽表:
方法名 返回值 描述 count() integer 返回數(shù)據(jù)項在T中出現(xiàn)的次數(shù) index() integer 返回第一個數(shù)據(jù)項在T中出現(xiàn)位置的索引,若值不存在,則拋出ValueError基礎(chǔ)公用函數(shù):
函數(shù)名 返回值 描述 len() integer 返回容器中的項目數(shù) enumerate() iterator for index, value of iterable 返回一個可迭代對象,其中以小元組的形式包裹數(shù)據(jù)項與正向索引的對應(yīng)關(guān)系 reversed() ... 詳情參見函數(shù)章節(jié) sorted() ... 詳情參見函數(shù)章節(jié) 獲取長度使用len()方法來獲取元組的長度。
返回int類型的值。
tup = ('A', 'B', 'C', 'D', 'E', 'F', 'G')print(len(tup))# 7
Python在對內(nèi)置的數(shù)據(jù)類型使用len()方法時,實際上是會直接的從PyVarObject結(jié)構(gòu)體中獲取ob_size屬性,這是一種非常高效的策略。
PyVarObject是表示內(nèi)存中長度可變的內(nèi)置對象的C語言結(jié)構(gòu)體。
直接讀取這個值比調(diào)用一個方法要快很多。
統(tǒng)計次數(shù)使用count()方法統(tǒng)計數(shù)據(jù)項在該元組中出現(xiàn)的次數(shù)。
返回int:
tup = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'A')aInTupCount = tup.count('A')print(aInTupCount)# 2查找位置
使用index()方法找到數(shù)據(jù)項在當(dāng)前元組中首次出現(xiàn)的位置索引值,如數(shù)據(jù)項不存在則拋出異常。
返回int。
tup = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'A')aInTupIndex = tup.index('A')print(aInTupIndex)# 0底層探究內(nèi)存開辟
Python內(nèi)部實現(xiàn)中,列表和元組還是有一定的差別的。
元組在創(chuàng)建對象申請內(nèi)存的時候,內(nèi)存空間大小便進(jìn)行了固定,后續(xù)不可更改(如果是傳入了一個可迭代對象,例如tupe(range(100)),這種情況會進(jìn)行擴(kuò)容與縮容,下面的章節(jié)將進(jìn)行探討研究)。
而列表在創(chuàng)建對象申請內(nèi)存的時候,內(nèi)存空間大小不是固定的,如果后續(xù)對其新增或刪除數(shù)據(jù)項,列表會進(jìn)行擴(kuò)容或者縮容機制。
元組創(chuàng)建空元組
若創(chuàng)建一個空元組,會直接進(jìn)行創(chuàng)建,然后將這個空元組丟到緩存free_list中。
元組的free_list最多能緩存 20 * 2000 個元組,這個在下面會進(jìn)行講解。
如圖所示:
元組轉(zhuǎn)元組這樣的代碼會進(jìn)行元組轉(zhuǎn)元組:
tup = tuple((1, 2, 3))
首先內(nèi)部本身就是一個元組(1, 2, 3),所以會直接將內(nèi)部的這個元組拿出來并返回引用,并不會再次創(chuàng)建。
代碼驗證:
>>> oldTup = (1, 2, 3)>>> id(oldTup)4384908128>>> newTup = tuple(oldTup)>>> id(newTup)4384908128>>>列表轉(zhuǎn)元組
列表轉(zhuǎn)元組會將列表中的每一個數(shù)據(jù)項都拿出來,然后放入至元組中:
tup = tuple([1, 2, 3])
所以你會發(fā)現(xiàn),列表和元組中的數(shù)據(jù)項引用都是相同的:
>>> li1 = ['A', 'B', 'C']>>> tup = tuple(li1)>>> print(id(li1[0]))4383760656>>> print(id(tup[0]))4383760656>>>可迭代對象轉(zhuǎn)元組
可迭代對象是沒有長度這一概念的,如果是可迭代對象轉(zhuǎn)換為元組,會先對可迭代對象的長度做一個猜想。
并且根據(jù)這個猜想,為元組開辟一片內(nèi)存空間,用于存放可迭代對象的數(shù)據(jù)項。
然后內(nèi)部會獲取可迭代對象的迭代器,對其進(jìn)行遍歷操作,拿出數(shù)據(jù)項后放至元組中。
如果猜想的長度太小,會導(dǎo)致元組內(nèi)部的內(nèi)存不夠存放下所有的迭代器數(shù)據(jù)項,此時該元組會進(jìn)行內(nèi)部的擴(kuò)容機制,直至可迭代對象中的數(shù)據(jù)項全部被添加至元組中。
rangeObject = range(1, 101)tup = tuple(rangeObject)// 假如猜想的是9// 第一步:+ 10 // 第二步:+ (原長度+10) * 0.25// 其實,就是增加【原長度*0.25 + 2.5】
如果猜想的長度太大,而實際上迭代器中的數(shù)據(jù)量偏少,則需要對該元組進(jìn)行縮容。
切片取值對元組進(jìn)行切片取值的時候,會開辟一個新元組用于存放切片后得到的數(shù)據(jù)項。
tup = (1, 2, 3)newSliceTup = tup[0:2]
當(dāng)然,如果是[:]的操作,則參照絕對引用,直接返回被切片的元組引用。
代碼驗證:
>>> id(tup)4384908416>>> newSliceTup = tup[0:2]>>> id(newSliceTup)4384904392緩存機制
free_list緩存
元組的緩存機制和列表的緩存機制不同。
元組的free_list會緩存0 - 19長度的共20種元組,其中每一種長度的元組通過單向鏈表橫向擴(kuò)展緩存至2000個,如下圖所示:
當(dāng)每一次的del操作有數(shù)據(jù)項的元組時,都會將該元組數(shù)據(jù)項清空并掛載至free_list單向鏈表的頭部的位置。
del 元組1del 元組2del 元組3
如下圖所示:
當(dāng)要創(chuàng)建一個元組時,會通過創(chuàng)建元組的長度,從free_list單向鏈表的頭部取出一個元組,然后將數(shù)據(jù)項存放進(jìn)去。
前提是free_list單向鏈表中緩存的有該長度的元組。
tup = (1, 2, 3)空元組與非空元組的緩存
空元組的緩存是一經(jīng)創(chuàng)建就緩存到free_list單向鏈表中。
而非空元組的緩存必須是del操作后才緩存到free_list單向鏈表中。
空元組的創(chuàng)建第一次創(chuàng)建空元組后,空元組會緩存至free_list單向鏈表中。
以后的每一次空元組創(chuàng)建,返回的其實都是同一個引用,也就是說空元組在free_list單向鏈表中即使被引用了也不會被銷毀。
>>> t1 = ()>>> id(t1)4511088712>>> t2 = ()>>> id(t2)4511088712非空元組的創(chuàng)建
當(dāng)free_list單向鏈表中有相同長度的元組時,會進(jìn)行引用并刪除。
這個在上圖中已經(jīng)示例過了,就是這個:
代碼示例:
$ python3Python 3.6.8 (v3.6.8:3c6b436a57, Dec 24 2018, 02:04:31)[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwinType 'help', 'copyright', 'credits' or 'license' for more information.>>> v1 = (None, None, None)>>> id(v1)4384907696>>> v2 = (None, None, None)>>> id(v2)4384908056>>> del v1>>> del v2 # ①>>> v3 = (None, None, None)>>> id(v3) # ②4384908056>>> v4 = (None, None, None)>>> id(v4) # ③4384907696>>>
①:free_list num_free=3 單向鏈表結(jié)構(gòu):v2 —> v1
②:創(chuàng)建了v3,拿出v2的空元組,填入v3數(shù)據(jù)項,故v2和v3的id值相等,證明引用同一個元組,此時free_list num_free=3 單向鏈表結(jié)構(gòu)為:—> v1
③:創(chuàng)建了v4,拿出v1的空元組,填入v4數(shù)據(jù)項,故v1和v4的id值相等,證明引用同一個元組
tupleobject.c源碼官網(wǎng)參考:點我跳轉(zhuǎn)
源碼一覽:點我跳轉(zhuǎn)
以下是截取了一些關(guān)鍵性源代碼,并且做上了中文注釋,方便查閱。
每一個元組都有幾個關(guān)鍵性的屬性:
Py_ssize_t ob_refcnt; // 引用計數(shù)器Py_ssize_t ob_size; // 數(shù)據(jù)項個數(shù),即元組大小PyObject *ob_item[1]; // 存儲元組中的數(shù)據(jù)項 [指針, ]
關(guān)于緩存free_list的屬性:
PyTuple_MAXSAVESIZE // 相當(dāng)于圖中的 free_num ,最大20,即縱向擴(kuò)展的緩存元組長度PyTuple_MAXFREELIST // 圖中 free_list 的橫向擴(kuò)展緩存列表個數(shù),最大2000創(chuàng)建元組
空元組
PyObject *PyTuple_New(Py_ssize_t size){ PyTupleObject *op; // 緩存相關(guān) Py_ssize_t i;// 元組的大小不能小于0 if (size < 0) {PyErr_BadInternalCall();return NULL; }#if PyTuple_MAXSAVESIZE > 0 // 創(chuàng)建空元組,優(yōu)先從緩存中獲取 // size = 0 表示這是一個空元組,從free_list[0]中獲取空元組 if (size == 0 && free_list[0]) {// op就是空元組op = free_list[0];// 新增空元組引用計數(shù)器 + 1Py_INCREF(op);#ifdef COUNT_ALLOCStuple_zero_allocs++;#endif// 返回空元組的指針return (PyObject *) op; }// 如果創(chuàng)建的不是空元組,且這個創(chuàng)建的元組數(shù)據(jù)項個數(shù)小于20,并且free_list[size]不等于空,表示有緩存 // 則從緩存中去獲取,不再重新開辟內(nèi)存 if (size < PyTuple_MAXSAVESIZE && (op = free_list[size]) != NULL) {// 拿出元組free_list[size] = (PyTupleObject *) op->ob_item[0];// num_free減1numfree[size]--;#ifdef COUNT_ALLOCSfast_tuple_allocs++;#endif/* Inline PyObject_InitVar */// 初始化,定義這個元組的長度為數(shù)據(jù)項個數(shù)#ifdef Py_TRACE_REFSPy_SIZE(op) = size;// 定義類型為 tuplePy_TYPE(op) = &PyTuple_Type;#endif// 增加一次新的引用_Py_NewReference((PyObject *)op); }// 如果是空元組 else#endif {// 檢查內(nèi)存情況,是否充足/* Check for overflow */if ((size_t)size > ((size_t)PY_SSIZE_T_MAX - sizeof(PyTupleObject) - sizeof(PyObject *)) / sizeof(PyObject *)) { return PyErr_NoMemory();}// 開辟內(nèi)存,并獲得一個元組:opop = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size);if (op == NULL) return NULL; }// 空元組的每一個槽位都是NULL for (i=0; i < size; i++)op->ob_item[i] = NULL;#if PyTuple_MAXSAVESIZE > 0 // 緩存空元組 if (size == 0) {free_list[0] = op;++numfree[0];Py_INCREF(op); /* extra INCREF so that this is never freed */ }#endif#ifdef SHOW_TRACK_COUNT count_tracked++;#endif // 將元組加入到GC機制中,用于內(nèi)存管理 _PyObject_GC_TRACK(op); return (PyObject *) op;}可迭代對象轉(zhuǎn)元組
這個不在tupleobject.c源碼中,而是在abstract.c源碼中。
官網(wǎng)參考:點我跳轉(zhuǎn)
源碼一覽:點我跳轉(zhuǎn)
PyObject *PySequence_Tuple(PyObject *v){ PyObject *it; /* iter(v) */ Py_ssize_t n; /* guess for result tuple size */ PyObject *result = NULL; Py_ssize_t j; if (v == NULL) {return null_error(); } /* Special-case the common tuple and list cases, for efficiency. */ // 如果是元組轉(zhuǎn)換元組,如 tup = (1, 2, 3) 或者 tup = ((1, 2, 3))直接返回內(nèi)存地址 if (PyTuple_CheckExact(v)) {Py_INCREF(v);return v; }// 如果是列表轉(zhuǎn)換元組,則執(zhí)行PyList_AsTuple(),將列表轉(zhuǎn)換為元組 // 如 tup = ([1, 2, 3]) if (PyList_CheckExact(v))return PyList_AsTuple(v); /* Get iterator. */ // 獲取迭代器, tup = (range(1, 4).__iter__()) it = PyObject_GetIter(v); if (it == NULL)return NULL; /* Guess result size and allocate space. */ // 猜想迭代器長度,也就是猜一下有多少個數(shù)據(jù)項 n = PyObject_LengthHint(v, 10); if (n == -1)goto Fail; // 根據(jù)猜想的迭代器長度,進(jìn)行元組的內(nèi)存開辟 result = PyTuple_New(n); if (result == NULL)goto Fail; /* Fill the tuple. */ // 將迭代器中每個數(shù)據(jù)項添加至元組中 for (j = 0; ; ++j) {PyObject *item = PyIter_Next(it);if (item == NULL) { if (PyErr_Occurred())goto Fail; break;}//如果迭代器中數(shù)據(jù)項比猜想的多,則證明開辟內(nèi)存不足需要需要進(jìn)行擴(kuò)容if (j >= n) { size_t newn = (size_t)n; /* The over-allocation strategy can grow a bit faster than for lists because unlike lists the over-allocation isn’t permanent -- we reclaim the excess before the end of this routine. So, grow by ten and then add 25%. */// 假如猜想的是9 // 第一步:+ 10 // 第二步:+ (原長度+10) * 0.25 // 其實,就是增加【原長度*0.25 + 2.5】newn += 10u; newn += newn >> 2;// 判斷是否超過了元組的數(shù)據(jù)項個數(shù)限制(sys.maxsize) if (newn > PY_SSIZE_T_MAX) {/* Check for overflow */PyErr_NoMemory();Py_DECREF(item);goto Fail; } n = (Py_ssize_t)newn; // 擴(kuò)容機制 if (_PyTuple_Resize(&result, n) != 0) {Py_DECREF(item);goto Fail; }}// 將數(shù)據(jù)項放入元組之中PyTuple_SET_ITEM(result, j, item); } /* Cut tuple back if guess was too large. */// 如果猜想的數(shù)據(jù)項太多,而實際上迭代器中的數(shù)據(jù)量偏少 // 則需要對該元組進(jìn)行縮容 if (j < n &&_PyTuple_Resize(&result, j) != 0)goto Fail; Py_DECREF(it); return result;Fail: Py_XDECREF(result); Py_DECREF(it); return NULL;}列表轉(zhuǎn)元組
這個不在tupleobject.c源碼中,而是在listobject.c源碼中。
官網(wǎng)參考:點我跳轉(zhuǎn)
源碼一覽:點我跳轉(zhuǎn)
PyObject *PyList_AsTuple(PyObject *v){ PyObject *w; PyObject **p, **q; Py_ssize_t n; // 例如:tup = ([1, 2, 3])// 進(jìn)行列表的驗證 if (v == NULL || !PyList_Check(v)) {PyErr_BadInternalCall();return NULL; }// 獲取大小,即數(shù)據(jù)項個數(shù) n = Py_SIZE(v); // 開辟內(nèi)存 w = PyTuple_New(n);// 如果是空元組 if (w == NULL)return NULL; // 執(zhí)行遷徙操作 p = ((PyTupleObject *)w)->ob_item; q = ((PyListObject *)v)->ob_item;// 將列表中數(shù)據(jù)項的引用,也給元組進(jìn)行引用 // 這樣列表中數(shù)據(jù)項和元組中的數(shù)據(jù)項都引用同1個對象 while (--n >= 0) {// 數(shù)據(jù)項引用計數(shù) + 1Py_INCREF(*q);*p = *q;p++;q++; }// 返回元組 return w;}切片取值
PyObject *PyTuple_GetSlice(PyObject *op, Py_ssize_t i, Py_ssize_t j)// 切片會觸發(fā)該方法{ // 如果對空元組進(jìn)行切片,則會拋出異常 if (op == NULL || !PyTuple_Check(op)) {PyErr_BadInternalCall();return NULL; } // 內(nèi)部的具體實現(xiàn)方法 return tupleslice((PyTupleObject *)op, i, j);}static PyObject *tupleslice(PyTupleObject *a, Py_ssize_t ilow, Py_ssize_t ihigh){ PyTupleObject *np; PyObject **src, **dest; Py_ssize_t i; Py_ssize_t len;// 計算索引位置 if (ilow < 0)ilow = 0; if (ihigh > Py_SIZE(a))ihigh = Py_SIZE(a); if (ihigh < ilow)ihigh = ilow; // 如果是[:]的操作,則直接返回源元組對象a的指針,即絕對引用 if (ilow == 0 && ihigh == Py_SIZE(a) && PyTuple_CheckExact(a)) {Py_INCREF(a);return (PyObject *)a; }// 初始化新的切片對象元組長度 len = ihigh - ilow;// 開始切片,創(chuàng)建了一個新元組np np = (PyTupleObject *)PyTuple_New(len); if (np == NULL)return NULL; src = a->ob_item + ilow; dest = np->ob_item;// 對源元組中的數(shù)據(jù)項的引用計數(shù)+1 for (i = 0; i < len; i++) {PyObject *v = src[i];Py_INCREF(v);dest[i] = v; }// 返回切片對象新元組np的引用 return (PyObject *)np;}緩存相關(guān)
static voidtupledealloc(PyTupleObject *op){ Py_ssize_t i; Py_ssize_t len = Py_SIZE(op); PyObject_GC_UnTrack(op); Py_TRASHCAN_SAFE_BEGIN(op)// 如果元組的長度大于0,則不是一個非空元組 if (len > 0) {i = len;// 將內(nèi)部的數(shù)據(jù)項引用計數(shù)都 - 1while (--i >= 0) Py_XDECREF(op->ob_item[i]);#if PyTuple_MAXSAVESIZE > 0// 準(zhǔn)備緩存,判斷num_free是否小于20,并且單向鏈表中的已緩存元組個數(shù)小于2000if (len < PyTuple_MAXSAVESIZE && numfree[len] < PyTuple_MAXFREELIST && Py_TYPE(op) == &PyTuple_Type){ // 添加至鏈表頭部 op->ob_item[0] = (PyObject *) free_list[len]; // 將num_free + 1 numfree[len]++; free_list[len] = op; goto done; /* return */}#endif } // 內(nèi)存中進(jìn)行銷毀 Py_TYPE(op)->tp_free((PyObject *)op);done: Py_TRASHCAN_SAFE_END(op)}
以上就是老Python帶你從淺入深探究Tuple的詳細(xì)內(nèi)容,更多關(guān)于Python Tuple的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. php測試程序運行速度和頁面執(zhí)行速度的代碼2. ASP中常用的22個FSO文件操作函數(shù)整理3. 三個不常見的 HTML5 實用新特性簡介4. Warning: require(): open_basedir restriction in effect,目錄配置open_basedir報錯問題分析5. ASP調(diào)用WebService轉(zhuǎn)化成JSON數(shù)據(jù),附j(luò)son.min.asp6. SharePoint Server 2019新特性介紹7. React+umi+typeScript創(chuàng)建項目的過程8. 無線標(biāo)記語言(WML)基礎(chǔ)之WMLScript 基礎(chǔ)第1/2頁9. ASP.NET Core 5.0中的Host.CreateDefaultBuilder執(zhí)行過程解析10. php網(wǎng)絡(luò)安全中命令執(zhí)行漏洞的產(chǎn)生及本質(zhì)探究
