Python中的sys.getsizeof(string)返回什么?

3

sys.getsizeof对于标准字符串返回什么?我注意到这个值比len返回的值高得多。


7
你试过阅读文档了吗? - Padraic Cunningham
2个回答

11

我将尝试从更广泛的角度回答你的问题。你在提到两个函数并比较它们的输出。首先让我们看一下它们的文档:

返回对象的长度(项目数量)。参数可以是序列(如字符串、字节、元组、列表或范围)或集合(如字典、集或冻结集)。

因此,在字符串的情况下,你可以期望len()返回字符数。

返回对象的大小(以字节为单位)。该对象可以是任何类型的对象。所有内置对象都将返回正确的结果,但这不一定适用于第三方扩展,因为它是实现特定的。

因此,在字符串的情况下(与许多其他对象一样),你可以期望sys.getsizeof()返回对象的字节数。没有理由认为它应该与字符数相同。

让我们看一些例子:

>>> first = "First"
>>> len(first)
5
>>> sys.getsizeof(first)
42

这个例子证实了大小并不等于字符数量。

>>> second = "Second"
>>> len(second)
6
>>> sys.getsizeof(second)
43

如果我们观察一个更长一个字符的字符串,我们会发现它的大小也增加了一字节。虽然我们不知道这是否是巧合。

>>> together = first + second
>>> print(together)
FirstSecond
>>> len(together)
11

如果我们将这两个字符串连接起来,它们的总长度等于它们长度的和,这是有道理的。

>>> sys.getsizeof(together)
48

与某些人的预期相反,合并后的字符串大小并不等于它们各自大小的总和。但它似乎仍然是长度加上某些东西。特别地,某些东西值为37字节。现在你需要意识到,在这种特定情况下,使用这个特定的Python实现等等,它才是37字节。你不应该依赖这点。尽管如此,我们可以看一下为什么它是37字节以及它们(大约)用于什么。

在CPython中(可能是Python最广泛使用的实现),字符串对象被实现为PyStringObject。这是C语言源代码(我使用的是2.7.9版本):

typedef struct {
    PyObject_VAR_HEAD
    long ob_shash;
    int ob_sstate;
    char ob_sval[1];

    /* Invariants:
     *     ob_sval contains space for 'ob_size+1' elements.
     *     ob_sval[ob_size] == 0.
     *     ob_shash is the hash of the string or -1 if not computed yet.
     *     ob_sstate != 0 iff the string object is in stringobject.c's
     *       'interned' dictionary; in this case the two references
     *       from 'interned' to this object are *not counted* in ob_refcnt.
     */
} PyStringObject;

您可以看到,这里有一个叫做PyObject_VAR_HEAD的东西,还有一个int,一个long和一个char数组。字符数组始终会包含一个额外的字符来存储字符串末尾的'\0'。加上intlongPyObject_VAR_HEAD,这就多了37个字节的空间。 PyObject_VAR_HEAD另一个C源文件中定义,并且它涉及到其他特定于实现的内容,如果您想要找出这37字节的具体位置,就需要进一步探索。此外,文档中提到,sys.getsizeof()

如果对象由垃圾收集器管理,则会添加额外的垃圾收集器开销。

总的来说,您不需要知道究竟是什么导致了这37个字节的差异,在这个答案中,我们为您提供了一些想法,帮助您找到更多信息,如果您确实需要的话。


要明确的是,在CPython上,“额外的垃圾收集器开销”不适用于str。这种额外开销适用于CPython的循环垃圾收集器跟踪的对象以及“叶子类型”(不能包含对其他对象的引用,因此不能成为循环引用链中的链接,例如strbytesintfloat等)。这些“叶子类型”不需要额外的GC链接来启用循环垃圾收集。相比之下,所有没有存储单一统一数据的集合类型(listtuplesetdict,用户定义的类等)都需要支付这种开销。 - undefined

2

引用文档:

以字节为单位返回对象的大小。该对象可以是任何类型的对象。所有内置对象都将返回正确的结果,但对于第三方扩展来说,这并不一定成立,因为它是实现特定的。

内置字符串不是简单的字符序列 - 它们是完整的对象,具有垃圾回收开销,这可能解释了您注意到的大小差异。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接