• python中bytes类型与str类型的区别以及python中str类型是怎么存储的


    先说说bytes类型与str类型的区别, 它们是完全不同的两种类型. bytes实际上就是整数数组(0到127). 它对应着str的一种encoding方式. unicode不是编码方式, 只是指定了code points. 比如UTF-8, UTF-16才是具体的编码方式. str类型是本文重点要说的. 但是这里说的是它的不同, 不同就是它的目的是表示human readable的形式, 既然存在内存也需要编码, 但具体是哪种编码不一定.

    根据这个回答, 用哪种存储方式由字符串来决定, 但一定不能是utf系列(utf-8/16/32), 因为必须用定长的存储方式. 可能是ascii, latin-1. 每一个字符可能用1/2/4字节存储, 总之必须定长.

    以及写字符串到文件的时候, 会用哪种编码?

    根据PEP393

    typedef struct {
      PyObject_HEAD
      Py_ssize_t length;
      Py_hash_t hash;
      struct {
          unsigned int interned:2;
          unsigned int kind:2;
          unsigned int compact:1;
          unsigned int ascii:1;
          unsigned int ready:1;
      } state;
      wchar_t *wstr;
    } PyASCIIObject;
    
    typedef struct {
      PyASCIIObject _base;
      Py_ssize_t utf8_length;
      char *utf8;
      Py_ssize_t wstr_length;
    } PyCompactUnicodeObject;
    
    typedef struct {
      PyCompactUnicodeObject _base;
      union {
          void *any;
          Py_UCS1 *latin1;
          Py_UCS2 *ucs2;
          Py_UCS4 *ucs4;
      } data;
    } PyUnicodeObject;
    
    

    原文中这个结构体其后的描述, 我觉得是这样的:

    • 注意到这是层次式的(a hierarchy of structures), 意思是说, PyCompactUnicodeObject中有一个PyASCIIObject _base; , 就是上一个结构体, 而PyUnicodeObject中又有PyCompactUnicodeObject _base;.

    • 不同的字符串会用不同的结构体, 具体来说:
      先引入compact的概念: Objects for which both size and maximum character are known at creation time are called "compact" unicode object

      我一开始看到的时候还奇怪, str不是可以做拼接么. 并不是, str就是常量, 拼接实际上是做替换. 有此为证:

      a="123"
      id(a)
      a+="shfkd"
      id(a) # 并不相同
      

      然后说, 不同的字符串具体会被分配为什么struct: 在compact的情况下, 最大字符<128, 用PyASCIIObject
      否则用PyCompactObject. 非compact, 用PyUnicodeObject

    吐槽一下, 这个回答user2240578这个回答, 明显与str的表示毫无关系.

    前面是阅读, 这个回答uniqueid的代码验证了这一点:

    >>> getsizeof('U0000007f')  
    50
    >>> getsizeof('U00000080') #----------The size of the string changes at x74 - x80 boundary but..
    74
    >>> getsizeof('U00000080U00000080') # ..the size of the code-unit is still one. so not UTF-8
    75
    
    >>> getsizeof('U000000ff')  
    74
    >>> getsizeof('U000000ffU000000ff')# (+1 byte)  
    75
    >>> getsizeof('U00000100')  
    76
    >>> getsizeof('U00000100U00000100') # Size change at byte boundary(+2 bytes). Rep is UCS-2.   
    78
    >>> getsizeof('U0000ffff') 
    76
    >>> getsizeof('U0000ffffU0000ffff') # (+ 2 bytes)
    78
    >>> getsizeof('U00010000')  
    80
    >>> getsizeof('U00010000U00010000') # (+ 4 bytes) Thes size of the code unit changes to 4 at byte boundary again.
    84
    

    为什么从一个到第二个, 字符数相同, 但是内存差那么多, 因为用了嵌套结构体, 第一行0x7f=127, 在ascii的范围内, 用的是PyASCIIObject, 第二个用的是PyCompactUnicodeObject, 后者的结构体包含前者, 大那么多就是应该的了.

    1字节的表示范围最大就是0xff, 可以看到8行与10行, 就是差1字节, 因为是0xff, 在表示范围内. 12和14, 是0x100, 超过1字节, 差时字节. 说明编码方式的确是由最大值决定的, 字符串与字符串的表示不同. 从18到20行, 再次发生了这种"跃迁", 因为2字节最大表示0xffff.

    总结一下要点:

    • 不同字符串用的struct不同.
    • 不同字符串根据最大字符的范围, 用的编码方式不同. 但无论用哪种编码方式用的编码都必须是定长的, 因此不会用UTF-8之类的.
  • 相关阅读:
    .NET Core开发日志——从搭建开发环境开始
    通过Docker构建TensorFlow Serving
    通过Jenkins在IIS上布署站点
    RabbitMQ in Depth札记——AMQ协议
    Web API对application/json内容类型的CORS支持
    ng-book札记——路由
    ng-book札记——HTTP
    ng-book札记——依赖注入
    UVA
    POJ
  • 原文地址:https://www.cnblogs.com/Tokubara/p/14398517.html
Copyright © 2020-2023  润新知