2016-11-22 3 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 с элементами, которые они содержат. То есть они содержат указатели на (общий) 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 s наследуют от 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 s хранит только указатели, дает неверное впечатление, что "Hello" имеет больший размер, чем кортеж, содержащий его.

Только для полноты, unicode__sizeof__ - это тот, который вычисляет это. Он действительно просто умножает длину строки с размером символа (который зависит от того, какой тип имеет символ 1, 2 и 4 байт).

Единственное, что я не получаю с кортежами, это то, почему это базовый размер (обозначается tb_basicsize) указан как sizeof(PyTupleObject) - sizeof(PyObject *). Это отбрасывает 8 байт из общего размера, возвращенного; Я не нашел никаких объяснений этому (пока).

+1

Другой верный ответ, но мне интересно, игнорируется ли тег cpython в этих вопросах python-insideals –

+0

Я задавался вопросом, что я сам @Chris_Rands. Некоторое время назад, просканировав теги top Q, я понял, что большинство людей приравнивают 'python-internals' к тому, как работает CPython, поэтому я просто перескакиваю с этим чувством :-) –

 Смежные вопросы

  • Нет связанных вопросов^_^