3.0 序

我们知道python中的字符串属于变长对象,当然和int也是一样,底层的结构体实例所维护的数据的长度,在对象没有定义的时候是不知道的。当然如果是python2的话,底层PyIntObject维护的就是一个long,显然在没创建的时候就知道是1。

可变对象维护的数据的长度只能在对象创建的时候才能确定,举个例子,我们只能在创建一个字符串或者列表时,才知道它们所维护的数据的长度,在此之前,我们对此是一无所知的。

注意我们在前面提到过可变对象和不可变对象的区别,在变长对象中,实际上也可以分为可变对象和不可变对象。list和str实例化之后都是变长对象,但是list实例所维护数据是可以动态变化的,但是str实例就不支持添加、删除等操作了。下面我们来研究一下python变长对象中的不可变对象。

3.1 PyUnicodeObject和PyObject_Type

在Python中,PyUnicodeObject是对字符串对象的实现。PyUnicodeObject是一个拥有可变长度内存的对象,这一点很好理解。因为对于表示"hi"和"satori"的两个不同的PyUnicodeObject对象,其内部所需要保存字符串(或者说n个char)的内存空间显然是不一样的。与此同时,PyUnicodeObject又是一个不可变对象,一旦创建之后,内部维护的数据就不可以再修改了。这一特性使得PyUnicodeObject对象可以作为dict的key;但与此同时,当进行多个字符串连接等操作时,也会使效率大大降低。

我们看看PyUnicodeObject的定义:

typedef struct {
PyCompactUnicodeObject _base;
union {
void *any;
Py_UCS1 *latin1;
Py_UCS2 *ucs2;
Py_UCS4 *ucs4;
} data; /* Canonical, smallest-form Unicode buffer */
} PyUnicodeObject; typedef struct {
PyASCIIObject _base;
Py_ssize_t utf8_length; /* Number of bytes in utf8, excluding the
* terminating \0. */
char *utf8; /* UTF-8 representation (null-terminated) */
Py_ssize_t wstr_length; /* Number of code points in wstr, possible
* surrogates count as two code points. */
} PyCompactUnicodeObject; typedef struct {
PyObject_HEAD
Py_ssize_t length; /* Number of code points in the string */
Py_hash_t hash; /* Hash value; -1 if not set */
struct {
unsigned int compact:1;
unsigned int ascii:1;
unsigned int ready:1;
unsigned int :24;
} state;
wchar_t *wstr; /* wchar_t representation (null-terminated) */
} PyASCIIObject;

可以看到PyUnicodeObject实现起来很复杂,这是因为在python中,默认都是Unicode。直接分析起来很费劲,我们可以阅读一篇文章,来看看python在存储字符串的时候是如何节省内存的,从而进一步认识PyUnicodeObject。链接如下:https://rushter.com/blog/python-strings-and-memory/,这里我给翻译一下。

python在存储字符串的时候如何节省内存

从python3开始,str类型使用的是Unicode。而根据编码的不同,Unicode的每个字符最大可以占到4字节,从内存的角度来说, 这种编码有时会比较昂贵

为了减少内存消耗并且提高性能,python的内部使用了三种方式表示Unicode

  • 每个字符一字节(Latin-1 编码)
  • 每个字符二字节(UCS-2 编码)
  • 每个字符四字节(UCS-4 编码)

在python编程中,所有字符串行为都是一致的,而且大多数时间我们都没有注意到差异。然而在处理大文本的时候,这种差异就会变得异常显著、甚至有些让人出乎意料

为了看到内部表示的差异,我们使用sys.getsizeof函数,返回一个对象所占的字节数

# -*- coding:utf-8 -*-
# @Author: WanMingZhu
# @Date: 2019/10/25 14:01
import sys
string = "hello"
print(sys.getsizeof(string)) # 54 # 1 bytes
print(sys.getsizeof(string + "!") - sys.getsizeof(string)) # 1 string2 = "你"
# 2 bytes
print(sys.getsizeof(string2 + "好") - sys.getsizeof(string2)) # 2
print(sys.getsizeof(string2)) # 76 string3 = "

《python解释器源码剖析》第3章--python中的str对象的更多相关文章

  1. 《python解释器源码剖析》第13章--python虚拟机中的类机制

    13.0 序 这一章我们就来看看python中类是怎么实现的,我们知道C不是一个面向对象语言,而python却是一个面向对象的语言,那么在python的底层,是如何使用C来支持python实现面向对象 ...

  2. 《python解释器源码剖析》第12章--python虚拟机中的函数机制

    12.0 序 函数是任何一门编程语言都具备的基本元素,它可以将多个动作组合起来,一个函数代表了一系列的动作.当然在调用函数时,会干什么来着.对,要在运行时栈中创建栈帧,用于函数的执行. 在python ...

  3. 《python解释器源码剖析》第9章--python虚拟机框架

    9.0 序 下面我们就来剖析python运行字节码的原理,我们知道python虚拟机是python的核心,在源代码被编译成字节码序列之后,就将有python的虚拟机接手整个工作.python虚拟机会从 ...

  4. 《python解释器源码剖析》第0章--python的架构与编译python

    本系列是以陈儒先生的<python源码剖析>为学习素材,所记录的学习内容.不同的是陈儒先生的<python源码剖析>所剖析的是python2.5,本系列对应的是python3. ...

  5. 《python解释器源码剖析》第1章--python对象初探

    1.0 序 对象是python中最核心的一个概念,在python的世界中,一切都是对象,整数.字符串.甚至类型.整数类型.字符串类型,都是对象.换句话说,python中面向对象的理念观测的非常彻底,面 ...

  6. 《python解释器源码剖析》第11章--python虚拟机中的控制流

    11.0 序 在上一章中,我们剖析了python虚拟机中的一般表达式的实现.在剖析一遍表达式是我们的流程都是从上往下顺序执行的,在执行的过程中没有任何变化.但是显然这是不够的,因为怎么能没有流程控制呢 ...

  7. 《python解释器源码剖析》第8章--python的字节码与pyc文件

    8.0 序 我们日常会写各种各样的python脚本,在运行的时候只需要输入python xxx.py程序就执行了.那么问题就来了,一个py文件是如何被python变成一系列的机器指令并执行的呢? 8. ...

  8. 《python解释器源码剖析》第7章--python中的set对象

    7.0 序 集合和字典一样,都是性能非常高效的数据结构,性能高效的原因就在于底层使用了哈希表.因此集合和字典的原理本质上是一样的,都是把值映射成索引,通过索引去查找. 7.1 PySetObject ...

  9. 《python解释器源码剖析》第4章--python中的list对象

    4.0 序 python中的list对象,底层对应的则是PyListObject.如果你熟悉C++,那么会很容易和C++中的list联系起来.但实际上,这个C++中的list大相径庭,反而和STL中的 ...

  10. 《python解释器源码剖析》第2章--python中的int对象

    2.0 序 在所有的python内建对象中,整数对象是最简单的对象.从对python对象机制的剖析来看,整数对象是一个非常好的切入点.那么下面就开始剖析整数对象的实现机制 2.1 初识PyLongOb ...

随机推荐

  1. IDEA 2017 安装和破解

    IDEA 2017 下载地址 链接:http://pan.baidu.com/s/1qXNa9UO 密码:9wwg 激活注册码:http://xidea.online 1-选择安装地址 2-选择安装的 ...

  2. Linux日常用的命令

    查看一个文件夹是的挂载路径,比如查看opt文件夹挂载在哪:df /opt root@iZ2zedo02x7n4nuc3lb4ueZ:~# df /opt Filesystem 1K-blocks Us ...

  3. Linux中权限控制ACL命令

    很多小伙伴觉得,Linux的权限管理命令不就是chown和chmod命令吗,什么时候有了ACL了? 什么是ACLACL是访问控制列表(Access Control List)的缩写,主要的目的是在提供 ...

  4. 【miscellaneous】IP多播技术及其编程

    标  题: IP多播技术及其编程 发信站: 幽幽黄桷兰 (Mon Jun 16 10:35:39 2003) 转信站: SMTH!maily.cic.tsinghua.edu.cn!news2.ues ...

  5. Centos7源码安装Apache和PHP

    源码安装Apache 安装需要的依赖 yum -y install gcc autoconf automake make pcre pcre-devel openssl openssl-devel​# ...

  6. [Comet OJ - Contest #6 C][48C 2279]一道树题_树

    一道树题 题目大意: 给定一棵树,边的编号为读入顺序.现在规定,区间$[L, R]$的贡献$S(L,R)$为把编号在该区间里的边都连上后,当前形成的森林中点数大于等于$2$的联通块个数. 求$\sum ...

  7. 【转帖】.NET的一点历史故事:作者的一些感想

    .NET的一点历史故事:作者的一些感想 https://mp.weixin.qq.com/s?__biz=MzAwNTMxMzg1MA==&mid=2654068684&idx=2&a ...

  8. redis 慢查询、Pipeline

    1.慢查询 简介 慢查询顾名思义是将redis执行命令较慢的命令记录下来,redis处理慢查询时是将慢查询记录到慢查询队列中 慢查询配置 slowlog-max-len 慢查询队列长度(记录多少条慢查 ...

  9. Spring Boot常用的注解以及含义<持续更新>

    1.@RestController和@RequestMapping注解 @RestController 和 @RequestMapping 注解是Spring MVC注解(它们不是Spring Boo ...

  10. Spring Cloud Feign接口返回流

    身无彩凤双飞翼,心有灵犀一点通. 服务提供者 @GetMapping("/{id}") public void queryJobInfoLogDetail(@PathVariabl ...