来自tweet here:
import sys
x = 'ñ'
print(sys.getsizeof(x))
int(x) #throws an error
print(sys.getsizeof(x))
我们得到74,然后是两个getsizeof
来电的77个字节。
看起来我们正在从失败的int调用中向对象添加3个字节。
来自twitter的更多示例(您可能需要重新启动python以将大小重置为74):
x = 'ñ'
y = 'ñ'
int(x)
print(sys.getsizeof(y))
77!
print(sys.getsizeof('ñ'))
int('ñ')
print(sys.getsizeof('ñ'))
74,然后是77。
答案 0 :(得分:71)
在CPython 3.6 requests a UTF-8 form of the string to work with中将字符串转换为int的代码:
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'
。这是因为string-to-int过程中的one of the earlier steps是
asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);
将所有空白字符转换为' '
,并将所有Unicode十进制数字转换为相应的ASCII数字。如果它不会改变任何内容,则此转换将返回原始字符串,但是当它确实进行更改时,它会创建一个新字符串,并且新字符串将获得创建UTF-8表示的字符串。
对于在一个字符串上调用int
看起来影响另一个字符串的情况,那些实际上是相同的字符串对象。在许多条件下,Python将重用字符串,就像Weird Implementation Detail Land一样,就像我们迄今为止所讨论的一样。对于'ñ'
,重复发生是因为这是Latin-1范围内的单字符字符串('\x00'
- '\xff'
)和实现stores and reuses those。