Python存储字符串时节省空间的方法

  

从Python 3开始,str类型代表着Unicode字符串。取决于编码的类型,一个Unicode字符可能会占4个字节,这个有些时候有点浪费内存。

  

出于内存占用以及性能方面的考虑,Python内部采用下面3种方式来存储Unicode字符:

  
      <李>一个字符占一个字节(latin - 1编码)   <李>一个字符占二个字节(ucs - 2编码)   <李>一个字符占四个字节(ucs - 4编码)   <李>   
  

使用Python进行开发的时候,我们会觉得字符串的处理都很类似,很多时候根本不需要注意这些差别。可是,当碰到大量的字符处理的时候,这些细节就要特别注意了。

  

我们可以做一些小实验来体会下上面三种方式的差别。方法系统。getsizeof用来获取一个对象所占用的字节,这里我们会用的到。

        在在在导入系统   在在在字符串='你好'   在在在sys.getsizeof(字符串)   54   在在在# 1字节编码   …sys。getsizeof(字符串+ !)- sys.getsizeof(字符串)   1   在在在# 2字节编码   …string2相等='你'   在在在sys。getsizeof (string2相等+ '好')- sys.getsizeof (string2相等)   2   在在在sys.getsizeof (string2相等)   76   在在在# 4字节编码   …string3=':蛇:'   在在在sys。getsizeof (string3 +:计算机)- sys.getsizeof (string3)   4   在在在sys.getsizeof (string3)   80年      

如上所示,当字符串的内容不同时,所采用的编码也会不同。需要注意的是,Python中每个字符串都会另外占用49 - 80字节的空间,用于存储额外的一些信息,比如哈希,字符串长度,字符串字节数和字符串标识。这么一来,一个空字符串会占用49个字节,也就好理解了。

  

我们可以通过cbytes直接获取一个对象的编码类型:

        进口ctypes   类PyUnicodeObject (ctypes.Structure):   #内部字段的字符串对象   _fields_=[(“ob_refcnt”, ctypes.c_long),   (“ob_type”ctypes.c_void_p),   (“长度”,ctypes.c_ssize_t),   (“希”,ctypes.c_ssize_t),   (“实习”,ctypes。c_uint, 2),   (“善良”,ctypes。c_uint, 3),   (“紧凑”ctypes。c_uint, 1),   (" ctypes ascii”。c_uint, 1),   (“准备好”,ctypes。c_uint, 1),   #……   #……   ]   def get_string_kind(字符串):   返回PyUnicodeObject.from_address (id (string)) .kind      

然后测试

        在在在get_string_kind(“你好”)   1   在在在get_string_kind('你的好)   2   在在在get_string_kind(':蛇:')   4      

如果一个字符串中的所有字符都能用ASCII表示,那么Python会使用latin - 1编码。简单说下,latin - 1用于表示前256个Unicode字符。它能支持很多拉丁语言,比如英语,瑞典语,意大利语等。不过,如果是汉语、日语、西伯尔语等非拉丁语言,latin - 1编码就行不通了,因为这些语言的文字的码位值(编码值)超过了1个字节的范围(0 - 255)。

        在在在奥德(' a ')   97   在在在奥德(“你”)   20320   在在在奥德(!)   33      

大部分语言文字使用2个字节(ucs - 2)来编码就已经足够了。4个字节(ucs - 4)的编码在保存特殊符号,emoji表情或者少见的语言文字的时候会用的到。

  

设想有一个10 gb的ASCII文本文件,我们准备将其读到内存里面去。如果你插入一个emoji表情到文件中,文件占用空间将会达到4倍。如果你处理NLP问题较多的话,这种差别你应该能经常体会到。

  

  

最常见的Unicode编码是utf - 8,但是Python内部并没有使用它。

  

utf - 8编码字符的时候,取决于字符的内容,占的空间在1 - 4个字节内发生变化。这是一种特别省空间的存储方式,但正因为这种变长的存储方式,导致字符串不能通过下标直接进行随机读取,只能遍历进行查找。比如,如果采用的是utf - 8编码的话,Python获取字符串[5]只能一个一个字符的进行扫描,直至找到目标字符。如果是定长编码的话也就没有问题了,要用一个下标定位一个字符,只需要用下标乘以指定长度(1、2或4)者就能确定。

  

  

Python中的空字符串和ASCII字符都会使用到字符串驻留(字符串实习)技术。怎么理解?你就把这些字符(串)看作是单例的就行,也就是说,两个相同内容的字符串如果使用了驻留的技术,那么内存里面其实就只开辟了一个空间。

Python存储字符串时节省空间的方法