在CPython 3.6中将字符串转换为int的代码要求字符串以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:
(assert(_PyUnicode_CHECK(op)), \
assert(PyUnicode_IS_READY(op)), \
PyUnicode_IS_COMPACT_ASCII(op) ? \
((char*)((PyASCIIObject*)(op) + 1)) : \
_PyUnicode_UTF8(op))
您可能还会想知道,为什么尺寸不会像一样改变'1'
。这就是U + FF11全长数字ONE,它int
等同于'1'
。这是因为string-to-int程序中较早的步骤之一是
asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);
它将所有空格字符' '
转换为并将所有Unicode十进制数字转换为相应的ASCII数字。如果此转换没有结束任何更改,则返回原始字符串,但是当进行更改时,它将创建一个新字符串,并且该新字符串是将创建UTF-8表示形式的字符串。
至于调用int
一个字符串看起来会影响另一个字符串的情况,则实际上是相同的字符串对象。在许多情况下,Python将重用字符串,正如到目前为止我们所讨论的一切一样,在Weird Implementation Detail领域中,这些条件都同样牢固。对于'ñ'
,发生重用是因为这是Latin-1范围('\x00'
- '\xff'
)中的单字符字符串,并且实现存储并重用了这些字符。