为什么这个Pythonstring的大小在一个失败的int转换上发生了变化
从这里的鸣叫 :
import sys x = 'ñ' print(sys.getsizeof(x)) int(x) #throws an error print(sys.getsizeof(x))
我们得到74,然后77字节的两个getsizeof
调用。
看起来我们正在从失败的int调用中向对象添加3个字节。
更多来自twitter的例子(你可能需要重新启动python重新设置为74):
x = 'ñ' y = 'ñ' int(x) print(sys.getsizeof(y))
77!
print(sys.getsizeof('ñ')) int('ñ') print(sys.getsizeof('ñ'))
74,然后77。
在CPython 3.6中将string转换为整数的代码请求使用string的UTF-8格式 :
buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen);
并且该string在第一次请求时创buildUTF-8表示并将其caching在string对象上 :
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表示。
你可能想知道为什么当string是像'40'
或'plain ascii text'
这样的大小不会改变。 那是因为如果string是“compact ascii”表示 ,Python不会创build一个单独的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全宽数字1,这等于'1'
。 这是因为string到int处理的早期步骤之一
asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);
它将所有空格字符转换为' '
,并将所有Unicode十进制数字转换为相应的ASCII数字。 这个转换返回原始的string,如果它最终没有改变任何东西,但是当它做了改变,它会创build一个新的string,新的string是获得创build的UTF-8表示的string。
至于在一个string上调用int
看起来像是影响另一个的情况,那些实际上是相同的string对象。 Python会重复使用string的条件有很多,就像我们之前讨论过的所有内容一样,它们都像“奇怪的实现细节”一样牢固。 对于'ñ'
,重复使用是因为这是拉丁文-1范围内的单字符string( '\x00'
– '\xff'
),并且实现存储 '\xff'
用了这些string。
根据这里的文档:
如果对象由垃圾收集器pipe理,getsizeof()将调用对象的sizeof方法并添加额外的垃圾回收器开销。
但是与getsizeof()没有任何关系有一件事是肯定的 :
它与sys
模块和sys.getsizeof()
方法没有任何关系,问题在于__sizeof__
方法。 没有getsizeof()
我可以重现错误:
x = 'ñ' print(x.__sizeof__()) #74 int('ñ') print(x.__sizeof__()) #77
并解释为什么发生了@ user2357112与接受的答案