代码之家  ›  专栏  ›  技术社区  ›  scharette

为什么unicode字符串在python 2和3中具有不同的内存占用?[副本]

  •  4
  • scharette  · 技术社区  · 7 年前

    这个问题已经有了答案:

    在python 2中,空字符串正好占据37个字节,

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

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

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

    现在我认为这是因为 在python 3中,所有字符串现在都是unicode . 但是,令我惊讶的是,这里有一些令人困惑的输出,

    蟒蛇2.7

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

    蟒蛇3.6

    >>>>print(sys.getsizeof(''))
    49
    >>>>print(sys.getsizeof('1'))
    50
    
    1. 空字符串的大小不同。
    2. 在python 2中添加字符时还需要4个字节,而在python 3中只需要一个字节。

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

    编辑

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

    2 回复  |  直到 7 年前
        1
  •  4
  •   jsbueno    7 年前

    当然,这是有原因的,但实际上,这对于任何实际目的都不重要。如果您有一个python系统,为了接近系统内存,您必须在内存中保留如此多的字符串,那么您应该通过(1)尝试在内存中延迟加载/创建字符串,或(2)使用面向字节的高效二进制结构来处理您的数据,例如麻木,或者巨蟒自己的 bytearray .

    空字符串文本(py2的unicode文本)的更改可能导致您正在查看的版本之间的任何实现细节,即使编写C代码来直接与python字符串交互,这也不重要:即使是那些文本也应该只通过api接触字符串。

    现在,为什么python 3中的字符串只增加了“1”字节,而python 2中的字符串增加了4字节,具体原因是 PEP 393 .

    在python 3.3之前,python中的任何(unicode)字符串都将为每个字符使用固定的2字节或固定的4字节内存——而使用本机代码的python解释器和python模块必须编译为仅使用其中一种。也就是说,即使版本匹配,由于在构建时获取的字符串宽度optoin,您最终也可能拥有不兼容的python二进制文件——构建被称为“窄构建”和“宽构建”。使用上面提到的PEP391,python字符串的字符大小取决于它包含的最宽的unicode码位的大小。包含前256个代码点中包含的点的字符串(相当于拉丁-1字符集)每个字符仅使用1个字节。

        2
  •  3
  •   Dietrich Epp    7 年前

    在内部,python 3现在以四种不同的编码方式存储字符串,并为每个字符串选择不同的编码。这些编码是ASCII、Latin-1、UCS-2和UTF-32。每个元素都能够表示不同的Unicode字符子集,并且具有索引处元素 也是索引处的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个字节…元素(我不愿说“字符”),这取决于编译时选项,它们不能混合。