2016-11-22 17 views
5

以下代碼會生成給定輸出。__sizeof__ str大於__sizeof__包含該字符串的元組

import sys 

print('ex1:') 
ex1 = 'Hello' 
print('\t', ex1.__sizeof__()) 

print('\nex2:') 
ex2 = ('Hello', 53) 
print('\t', ex2.__sizeof__()) 

輸出:

ex1: 
    54  
ex2: 
    40 

爲什麼__sizeof__()打印較小的結果,當第二個元素被認爲?產量不應該更大?我從this answer知道我應該使用sys.getsizeof(),但行爲似乎很奇怪。我正在使用Python 3.5.2

此外,由於@Herbert指出,'Hello'佔用比('Hello',)更多的內存,這是tuple。爲什麼是這樣?

+0

你的第一個對象不是一個元組,它是括號內的一個字符串。 – Kasramvd

回答

13

這是由於這樣的事實:tuple對象(我敢肯定,除了從字符串中的所有容器)通過包括各自含量的實際尺寸,而是通過計算尺寸評估其大小指向PyObject s指示它們包含的元素。也就是說,他們持有指向包含(通用)PyObject的指針,這就是它的總體規模。

這在Data Model chapter of the Python Reference手冊被暗示:

某些對象包含引用對其他對象;這些被稱爲容器。容器的例子是元組,列表和字典。引用是容器值的一部分。

(我強調這個詞引用)

In PyTupleType,其中在tuple類型的信息都包含一個結構,我們看到tp_itemsize領域具有sizeof(PyObject *)作爲其值:

PyTypeObject PyTuple_Type = { 
    PyVarObject_HEAD_INIT(&PyType_Type, 0) 
    "tuple", 
    sizeof(PyTupleObject) - sizeof(PyObject *), 
    sizeof(PyObject *), // <-- sizeof pointer to PyObject's 

32位構建和64位建立的Python有sizeof(PyObject *)等於8個字節。

這是要乘以tuple實例中包含的項目數量的值。當我們看object_size__sizeof__方法tuple期從object繼承(檢查object.__sizeof__ is tuple.__sizeof__),我們可以看到這顯然:

static PyObject * 
object_sizeof(PyObject *self, PyObject *args) 
{ 
    Py_ssize_t res, isize; 

    res = 0; 
    isize = self->ob_type->tp_itemsize; 
    if (isize > 0) 
     res = Py_SIZE(self) * isize; // <-- num_elements * tp_itemsize 
    res += self->ob_type->tp_basicsize; 

    return PyLong_FromSsize_t(res); 
} 

看到isize(從tp_itemsize獲得)由Py_SIZE(self)成倍增加,這是另一個宏抓取ob_size,指示tuple內的元素的數量。

這就是爲什麼即使我們創建了一個元組的實例裏面有點大字符串:它裏面

t = ("Hello" * 2 ** 10,) 

與元素的大小爲:

t[0].__sizeof__()   # 5169 

元組的大小實例:

t.__sizeof__()   # 32 

等於一個簡單"Hello"裏面:

t2 = ("Hello",) 
t[0].__sizeof__()   # 54 
t2.__sizeof__()   # 32 Tuple size stays the same. 

對於字符串,每個單獨的字符增加從str.__sizeof__返回的值。這與tuple僅存儲指針這一事實相比,給出了令人誤解的印象,即"Hello"比包含它的元組具有更大的尺寸。

只是爲了完整性,unicode__sizeof__是計算這個。它實際上只是將字符串的長度與字符大小相乘(這取決於字符的種類是1,24字節字符)。

我沒有得到元組唯一的事情就是爲什麼它的基本大小(由tb_basicsize表示)被列爲sizeof(PyTupleObject) - sizeof(PyObject *)。這從返回的整體大小中刪除8字節;我還沒有找到任何解釋(尚未)。

+1

另一個最好的答案,但我不知道是否在這些python-internals問題上忽略了cpython標籤 –

+0

我想知道我自己@Chris_Rands。前一段時間,在瀏覽標籤頂部Q之後,我意識到大多數人將'python-internals'與'CPython'的工作方式等同起來,所以我只是隨着這種情緒而搖擺:-) –