为什么Unicode字符串在Python 2和3中占用的内存不同?

时间:2018-08-07 17:37:36

标签: python python-3.x python-2.7 memory unicode

在Python 2中,一个空字符串恰好占据了37个字节,

>>>> print sys.getsizeof('')
37

在Python 3.6中,相同的调用将输出49个字节,

>>>> print(sys.getsizeof(''))
49

现在我认为这是由于在Python 3中所有字符串现在都是Unicode 所致。但是,令我惊讶的是,这里有一些令人困惑的输出,

Python 2.7

>>>> print sys.getsizeof(u'')
52
>>>> print sys.getsizeof(u'1')
56

Python 3.6

>>>>print(sys.getsizeof(''))
49
>>>>print(sys.getsizeof('1'))
50
  1. 一个空字符串的大小不相同。
  2. 在Python 2中添加字符时需要4个额外的字节,而对于Python 3仅需要一个字节

为什么两个版本的内存占用量不同?

编辑

我指定了我的python环境的确切版本,因为不同的Python 3版本之间存在差异。

2 个答案:

答案 0 :(得分:4)

当然有原因,但实际上,对于任何实际目的都没有关系。如果您有一个Python系统,其中必须在内存中保留这么多字符串以接近系统内存,则应通过以下方法对其进行优化:(1)尝试延迟加载/创建内存中的字符串,或者(2)使用一个字节面向对象的高效二进制结构来处理您的数据,例如Numpy提供的数据或Python自己的bytearray

对空字符串文字(Py2之前的Unicode文字)的更改可能依赖于您正在查看的版本之间的任何实现细节,即使编写C代码直接与Python字符串进行交互也没关系:即使这些仅通过API触摸字符串。

现在,为什么Python 3中的字符串仅将其大小增加“ 1”个字节,而在Python 2中将其大小增加4个字节的具体原因是PEP 393

在Python 3.3之前,Python中的任何(unicode)字符串将为每个字符使用固定的2个字节或固定的4个字节的内存-并且使用本机代码的Python解释器和Python模块必须编译为仅使用以下一种这些种类。即即使版本匹配,您仍然可能拥有不兼容的Python二进制文件,这是由于在构建时拾取了字符串宽度的视标-这些构建被称为“窄构建”和“宽构建”。使用上述PEP 391,Python字符串在实例化时将确定其字符大小,具体取决于其包含的最宽的Unicode代码点的大小。包含前256个代码点(等效于Latin-1字符集)中包含的点的字符串,每个字符仅使用1个字节。

答案 1 :(得分:3)

内部,Python 3现在以四种不同的编码存储字符串,并为每个字符串选择不同的编码。这些编码为ASCII,LATIN-1,UCS-2和UTF-32。每个字符都能够表示Unicode字符的不同子集,并且具有有用的属性,即索引 i 处的元素也是索引 i 处的Unicode代码点。

In [1]: import sys

In [2]: sys.getsizeof('\xFF')
Out[2]: 74

In [3]: sys.getsizeof('X\xFF')
Out[3]: 75

In [4]: sys.getsizeof('\u0100')
Out[4]: 76

In [5]: sys.getsizeof('X\u0100')
Out[5]: 78

In [6]: sys.getsizeof('\U00010000')
Out[6]: 80

In [7]: sys.getsizeof('X\U00010000')
Out[7]: 84

您会看到,在字符串中添加一个附加字符(在这种情况下为'X'会导致该字符串占用额外的空间,具体取决于字符串其余部分中包含的值。

此系统在PEP-0393中提出,并在Python 3.3中实现。 Python的早期版本使用较旧的unicode表示形式,该表示形式通常每个元素使用2或4个字节(我犹豫要说“字符”),具体取决于编译时选项,并且不能混合使用。< / p>