CPython 3.6 中将字符串转换为整数的代码requests a UTF-8 form of the string to work with:
buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen);
字符串在第一次被请求时创建 UTF-8 表示,caches it on the string object:
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" representation 中,Python 不会创建单独的 UTF-8 表示。它returns the ASCII representation directly,已经是有效的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'。那是因为one of the earlier steps在string-to-int过程中是
asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);
将所有空白字符转换为' ',并将所有 Unicode 十进制数字转换为相应的 ASCII 数字。如果最终没有更改任何内容,则此转换返回原始字符串,但是当它进行更改时,它会创建一个新字符串,而新字符串就是创建 UTF-8 表示的那个。
至于在一个字符串上调用int 看起来会影响另一个字符串的情况,它们实际上是同一个字符串对象。 Python 将在许多条件下重用字符串,所有这些都在 Weird Implementation Detail Land 中与我们迄今为止讨论的所有内容一样牢固。对于'ñ',会发生重用,因为这是拉丁1 范围内的单字符字符串('\x00'-'\xff'),以及实现stores and reuses those。