为什么这个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与接受的答案