为什么这个Python字符串的大小在失败的int转换时发生变化?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (54)

从这里:

import sys
x = 'ñ'
print(sys.getsizeof(x))
int(x) #throws an error
print(sys.getsizeof(x))

我们得到74个,然后77个字节的两个getsizeof调用。

看起来我们正在从失败的int调用中向对象添加3个字节。

更多示例(可能需要重新启动python才能将大小重置为74):

x = 'ñ'
y = 'ñ'
int(x)
print(sys.getsizeof(y))

77!

print(sys.getsizeof('ñ'))
int('ñ')
print(sys.getsizeof('ñ'))

74,然后77

提问于
用户回答回答于

在CPython 3.6中将字符串转换为整数的代码请求使用字符串的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:

#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,它int等同于'1'。这是因为字符串到整数处理的早期步骤之一

asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);

它将所有空格字符' '转换为并将所有Unicode十进制数字转换为相应的ASCII数字。如果该转换最终不会改变任何内容,则该转换将返回原始字符串,但当它进行更改时,会创建一个新字符串,并且新字符串将获得创建的UTF-8表示形式。

至于调用int一个字符串看起来像是影响另一个字符串的情况,那些实际上是相同的字符串对象。Python会重复使用字符串的条件有很多,就像我们迄今为止所讨论过的所有内容一样,它们在Weird Implementation Detail Land中都是如此。对于'ñ',重用是因为这是一个单字符字符串的Latin-1的范围内('\x00'- '\xff'),和实现存储和重用那些

用户回答回答于

根据这里的文档:

如果对象由垃圾回收器管理,getsizeof()将调用对象的sizeof方法并添加额外的垃圾回收器开销。

但是与getsizeof()没有任何关系。有 一件事是肯定的

它与模块没有任何关系sys,而且方法sys.getsizeof(),问题与__sizeof__方法有关。没有它,我可以重现错误getsizeof()

x = 'ñ'
print(x.__sizeof__())
#74
int('ñ')
print(x.__sizeof__())
#77

扫码关注云+社区

领取腾讯云代金券