Ответ 1
Код, преобразующий строки в int в 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'
. Это потому, что если строка находится в "компактном 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 FULLWIDTH DIGIT ONE, который int
рассматривает как эквивалент '1'
. Это потому, что один из предыдущих шагов в процессе "строка-в-ин"
asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);
который преобразует все пробельные символы в ' '
и преобразует все десятичные разряды Unicode в соответствующие цифры ASCII. Это преобразование возвращает исходную строку, если она ничего не меняет, но когда она вносит изменения, она создает новую строку, а новая строка - та, которая получает созданное представление UTF-8.
Что касается случаев, когда вызов int
в одной строке выглядит так, как будто он влияет на другой, это фактически один и тот же строковый объект. Есть много условий, при которых Python будет использовать строки, все так же твердо в Weird Implementation Detail Land, как все, что мы обсуждали до сих пор. Для 'ñ'
повторное использование происходит потому, что это односимвольная строка в диапазоне Latin-1 ('\x00'
- '\xff'
), а реализация хранит и повторно использует те.