Почему размер этой строки Python изменяется при неудачном преобразовании int

Из твита здесь :

import sys
x = 'ñ'
print(sys.getsizeof(x))
int(x) #throws an error
print(sys.getsizeof(x))

Мы получаем 74, а затем 77 байтов для двух вызовов getsizeof.

Похоже, что мы добавляем 3 байта к объекту из неудачного вызова int.

Еще несколько примеров из твиттера (вам может потребоваться перезапустить python, чтобы сбросить размер обратно до 74):

x = 'ñ'
y = 'ñ'
int(x)
print(sys.getsizeof(y))

77

print(sys.getsizeof('ñ'))
int('ñ')
print(sys.getsizeof('ñ'))

74, затем 77.

70 голосов | спросил jeremycg 1 32017vEurope/Moscow11bEurope/MoscowWed, 01 Nov 2017 22:21:49 +0300 2017, 22:21:49

1 ответ


0

Код, который преобразует строки в целые в CPython 3.6 запрашивает форму строки UTF-8 для работы с :

buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen);

и строка создает представление UTF-8 при первом запросе и кэширует его в строковом объекте :

if (PyUnicode_UTF8(unicode) == NULL) {
    assert(!PyUnicode_IS_COMPACT_ASCII(unicode));
    bytes = _PyUnicode_AsUTF8String(unicode, NULL);
    if (bytes == NULL)
        return NULL;
    _PyUnicode_UTF8(unicode) = PyObject_MALLOC(PyBytes_GET_SIZE(bytes) + 1);
    if (_PyUnicode_UTF8(unicode) == NULL) {
        PyErr_NoMemory();
        Py_DECREF(bytes);
        return NULL;
    }
    _PyUnicode_UTF8_LENGTH(unicode) = PyBytes_GET_SIZE(bytes);
    memcpy(_PyUnicode_UTF8(unicode),
              PyBytes_AS_STRING(bytes),
              _PyUnicode_UTF8_LENGTH(unicode) + 1);
    Py_DECREF(bytes);
}

Дополнительные 3 байта предназначены для представления UTF-8.


Вам может быть интересно, почему размер не изменяется, если строка имеет вид '40' или 'plain ascii text'. Это потому, что если строка находится в представлении "Compact Ascii" , Python не создает отдельное представление UTF-8. непосредственно возвращает представление ASCII , что уже действующий UTF-8:

#define PyUnicode_UTF8(op)                              \
    (assert(_PyUnicode_CHECK(op)),                      \
     assert(PyUnicode_IS_READY(op)),                    \
     PyUnicode_IS_COMPACT_ASCII(op) ?                   \
         ((char*)((PyASCIIObject*)(op) + 1)) :          \
         _PyUnicode_UTF8(op))

Вы также можете задаться вопросом, почему размер не изменяется для чего-то вроде '1'. Это U + FF11 ПОЛНАЯ ЦИФРА ОДНА, которую int воспринимает как '1'. Это потому, что один из предыдущих шагов в Процесс строки в int - это

asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);

, который преобразует все пробельные символы в ' ' и преобразует все десятичные цифры Unicode в соответствующие цифры ASCII. Это преобразование возвращает исходную строку, если в конечном итоге она ничего не меняет, но когда она действительно вносит изменения, она создает новую строку, и новая строка является той, которая получает созданное представление UTF-8.


Что касается случаев, когда вызов int для одной строки выглядит так, как будто она влияет на другую, то это фактически один и тот же строковый объект. Есть много условий, при которых Python будет повторно использовать строки, все так же твердо в Странной Стране Деталей Реализации, как и все, что мы обсуждали до сих пор. Для 'ñ' повторное использование происходит потому, что это односимвольная строка в диапазоне Latin-1 ('\x00' - '\xff') и реализация сохраняет и повторно использует эти .

ответил user2357112 1 32017vEurope/Moscow11bEurope/MoscowWed, 01 Nov 2017 22:51:33 +0300 2017, 22:51:33

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132