python小数据池(内存地址)

今天来学习认识一下python中的小数据池。

我们都知道 是用来作比较,要是两个变量的数值相等,

用比较返回的bool值会是True:

a = 1000

b = 1000

print(a == b) #返回True

== 比较的是数值

如果我们用a is b这样的方式呢?

注意要测试内存地址is()和接下来的id()方法等都不要在pyCharm (python IDE)中测试,

而是要打开python自带的IDE或直接cmd环境下测试才能得出效果。

(PyCharm的话会直接放同一个内存地址了,不是真实生产环境。)

is 比较的是内存地址,

print(a is b) #返回的是False

"==" 和 "is" 的区别:

前者是相等性比较,

比较的是两个对象中的值是否相等,后者是一致性比较,比较的是两个对象的内存空间地址是否相同。

如果内存地址相同,那么它们的值肯定也是一样的,因此,如果 “is” 返回 True,那么 “” 一定也返回 True,反之却不成立。有且当仅比较的两个变量指向同一个对象时 "is" 才返回 True,而 "" 最终取决于对象的 eq() 方法,本质上两个变量进行 "==" 比较操作调用的是对象的 eq() 方法。

查看内存地址我们使用的是id()方法:

print(id(a)) #返回的是内存地址,id门牌号之类

print(id(b))



若是将

a = 1000

b = a

再判断a is b又如何?

python一切皆是对象,和liunx一切皆文件有点异曲同工之处。

对象是通过引用传递的。在赋值时,不管这个对象是新创建的,还是一个已经存在的,都是将该对象的引用赋值给变量。

所以这里a实际上和b是同一个对象,a is b为true!

>>> c = 256
>>> d = 256
>>> c is d
True >>> e = 257
>>> f = 257
>>> e is f
False

将c赋值整型值256,d也为256,e为257,f为257。

当把c与d,e与f进行is操作时,却发现两者的布尔值结果不同。

为什么呢?

这是由python中的整型对象的缓冲池机制引起的。

在python中几乎所有的内建对象,都会有自己所特有的对象池机制。

小数据池 (注意只有字符串和数值有这个概念)

在一定范围之内的,共用同一个内存地址。

数字 -5~256 节省空间(内存),共用的都是一个小数据池(指向的是同一个内存地址)

小整数对象[-5, 257]在python中是共享的

(注,用列表表示是因为python中含首不含尾,所以[-5,257]表示的范围也就是数字 -5~256。)

整数对象都是从缓冲池中获取的。

整数对象回收时,内存并不会归还给系统,而是将其对象的ob_type指向free_list,供新创建的整数对象使用

1.小整数对象——小整型对象池

[small_ints的链表]

在实际编程中,数值比较小的整数,比如1,2,33等,会非常频繁的出现。

python中,所有的对象都存在于系统堆上。

如果某个小整数出现的次数非常多,那么python将会出现大量的malloc/free操作,这样大大降低了运行效率,而且会造成大量的内存碎片,严重影响Python的整体性能。

所以在python2.5乃至3.6中,将小整数位于[-5,257)之间的数,缓存在小整型对象池中。

2.大整数对象——通用整数对象池

python将小整型数完全的缓存在了小对象缓存池中了。

而那些大整数对象呢?

python运行环境也有提供一块内存空间供大整数轮流使用。

这块内存空间就是PyIntBlock。

通常称为通用整数对象池。

所以大整数其实也是有缓存的。

该对象池使用链表组织,哪怕两个大整数变量有着相同的值,但是在链表中确是不同的节点。不再是一个对象了。

字符串intern

关于字符串的intern内存驻留机制:

Incomputer science, string interning is a method of storing only onecopy of each distinct string value, which must be immutable. Interning strings makes some stringprocessing tasks more time- or space-efficient at the cost of requiring moretime when the string is created or interned. The distinct values are stored ina string intern pool. --引自维基百科

译:

在计算机科学中,string interning是一种只存储每个不同字符串值的onecopy的方法,它必须是不可变的。连接字符串使得一些stringprocessing任务更费时——或者更节省空间,因为在创建或插入字符串时需要moretime。不同的值存储在字符串驻留池中。

也就是说值相同的字符串对象只会保存一份,是共用的,所以字符串必须是不可变对象。

就跟小整数对象一样,相同的数值只要保存一份就行了,没必要用不同对象来区分。

同时以上也说到了这样做的优缺点:

优点:能够提高一些字符串处理任务在时间和空间上的性能;需要值相同的字符串的时候(比如标识符),直接从池里拿来用,避免频繁的创建和销毁,提升效率,节约内存。

缺点:在创建或插入字符串时会花费更多的时间。

注意事项

1、拼接字符串

由于字符串的改动不是inplace的操作,需要新建对象,因此不推荐使用+来拼接字符串,推荐使用join函数,因为join函数在拼接字符串之前会计算所有字符串的长度,然后逐一拷贝,仅新建一次对象。

2、字符串驻留限制

仅包含下划线(_)、字母和数字的字符串会启用字符串驻留机制驻留机制。因为解释器仅对看起来像python标识符的字符串使用intern()方法,而python标识符正是由下划线、字母和数字组成。

python默认只会对由字符

"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"构成字符串进行intern。

这部分的逻辑在codeobject.c中的函数PyCode_New中:在该函数中,会调用all_name_chars,检查字符串是否全是由简单的字符组成,判断通过的字符串才会进行intern处理。

这里的分析是对常量而言,对于计算得出的字符串,也是不做intern的。

python2中可以用intern()来对除此外的字符串进行处理使其共用一个内存空间,python3中不知为何对intern取消了支持。可能怕引起混乱吧,反正就默认了对那些看起来像是python标识符的进行intern。

例:python27中支持intern()

python3中使用intern()会直接报错。

>>> s3 = intern('hello!')
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
s3 = intern('hello!')
NameError: name 'intern' is not defined

3、字符串驻留时机

字符串只会在编译时进行驻留,而不是在运行时。

例:

>>> s5 = 'tiele'
>>> s6 = 'mao'
>>> 'tiele' + 'mao' is 'tielemao'
True
>>> s5 + s6 is 'tielemao'
False

实现 Intern 机制的就好比是通过维护一个字符串储蓄池,这个池子是一个字典结构,如果字符串已经存在于池子中了就不再去创建新的字符串,直接返回之前创建好的字符串对象,如果之前还没有加入到该池子中,则先构造一个字符串对象,并把这个对象加入到池子中去,方便下一次获取。

短字符串缓冲池characters

另外,字符串除了有intern机制缓存字符串之外,还有一种专门的短字符串缓冲池characters。用于缓存字符串长度为1的PyStringObject对象。

变长对象

在Python世界中将对象分为两种:

一种是定长对象,比如整数,整数对象定义的时候就能确定它所占用的内存空间大小,另一种是变长对象,在对象定义时并不知道是多少,比如:str,list, set, dict等。

同样都是字符串对象,不同字符串对象所占用的内存是不一样的,这就是变长对象,对于变长对象,在对象定义时是不知道对象所占用的内存空间是多少的。

字符串对象在Python内部用PyStringObject表示,PyStringObject和PyIntObject一样都属于不可变对象,对象一旦创建就不能改变其值。

(注意:变长对象和不可变对象是两个不同的概念)。

总结:

  1. 字符串用PyStringObject表示
  2. 字符串属于变长对象
  3. 字符串属于不可变对象
  4. 字符串用intern机制提高python的效率
  5. 字符串有专门的缓冲池存储长度为1的字符串对象

本文大量引用和参考链接如下:

https://foofish.net/python_str_inplements.html 《python字符串对象实现原理》

https://foofish.net/python_int_implement.html 《python整数对象实现原理》

https://blog.csdn.net/u011300968/article/details/77160619 《Python的字符串驻留》

end

铁乐与猫

2018-3-26

铁乐学Python_day06-整数和字符串小数据池的更多相关文章

  1. python基础之小数据池、代码块、编码和字节之间换算

    一.代码块.if True: print(333) print(666) while 1: a = 1 b = 2 print(a+b) for i in '12324354': print(i) 虽 ...

  2. python之路day06--python2/3小区别,小数据池的概念,编码的进阶str转为bytes类型,编码和解码

    python2#print() print'abc'#range() xrange()生成器#raw_input() python3# print('abc')# range()# input() = ...

  3. python基础之小数据池

    一,id,is,== 在Python中,id是什么?id是内存地址,比如你利用id()内置函数去查询一个数据的内存地址: name = '太白' print(id(name)) # 158583128 ...

  4. python代码块,小数据池,驻留机制深入剖析

    一,什么是代码块. 根据官网提示我们可以获知: 根据提示我们从官方文档找到了这样的说法: A Python program is constructed from code blocks. A blo ...

  5. Python基础学习Day6 is id == 区别,代码块,小数据池 ---->>编码

    一.代码块 Python程序是由代码块构造的.块是一个python程序的文本,他是作为一个单元执行的. 代码块:一个模块,一个函数,一个类,一个文件等都是一个代码块. 而作为交互方式输入的每个命令都是 ...

  6. python基础之小数据池、代码块、编码

    一.代码块.if True: print(333) print(666) while 1: a = 1 b = 2 print(a+b) for i in '12324354': print(i) 虽 ...

  7. python小数据池,代码块的最详细、深入剖析

    代码块: Python程序是由代码块构造的.块是 一个python程序的文本,他是作为一个单元执行的. 代码块:一个模块,一个函数,一个类,一个文件等都是一个代码块. 而作为交互方式输入的每个命令都是 ...

  8. 五.python小数据池,代码块的最详细、深入剖析

    一,id,is,== 在Python中,id是什么?id是内存地址,那就有人问了,什么是内存地址呢? 你只要创建一个数据(对象)那么都会在内存中开辟一个空间,将这个数据临时加在到内存中,那么这个空间是 ...

  9. python 小数据池,代码块, is == 深入剖析

    python小数据池,代码块的最详细.深入剖析   一. id is == 二. 代码块 三. 小数据池 四. 总结 一,id,is,== 在Python中,id是什么?id是内存地址,那就有人问了, ...

随机推荐

  1. 这个PHP无解深坑,你能解出来吗?(听说能解出来的都很秀)

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由horstxu发表于云+社区专栏 1. 问题背景 PHP Laravel框架中的db migration是比较常用的一个功能了.在每个 ...

  2. C语言理论知识

    C语言-----理论部分   一:软件开发概述1.程序语言的发展:机器语言-->汇编语言-->高级语言.2.软件开发的基本步骤与方法:分析问题,建立数学模型-->确定数据结构和算法- ...

  3. SparkSQL简介

    1.SparkSQL的发展历程 1.1 Hive and Shark SparkSQL的前身是Shark,给熟悉RDBMS但又不理解MapReduce的技术人员提供快速上手的工具,Hive应运而生,它 ...

  4. Java简单的RPC实现(一)

    RPC使用java最基本的,传输层使用Socket,序列化使用Serializable,java 动态代理模式,但是未实现消息注册等相关信息 大道至简 server端 package com.rpc. ...

  5. lucene源码分析(5)lucence-group

    1. 普通查询的用法 org.apache.lucene.search.IndexSearcher public void search(Query query, Collector results) ...

  6. ShellExecute 启动外部程序 参数详细介绍

    ShellExecute的功能是运行一个外部程序(或者是打开一个已注册的文件.打开一个目录.打印一个文件等等),并对外部程序有一定的控制. 目录 1基本简介 2原型参数 3返回值 4例子 5特殊用法 ...

  7. ASP.NET 省市县三联动 (包含用户控件)

    将压缩文件下载解压后,将用户控件拖到解决方案里,直接可以拖到需要用到的页面里 使用: 数据库是最新的(父子级关系表结构----Region2016.sql) 右键记事本打开,放在sqlServerl里 ...

  8. 通向全栈之路——(4)nginx反向代理配置

    1.安装nginx:sudo apt-get install nginx2.新建配置文件:cd /etc/nginx/conf.dsudo vi XXX-cn-8080.conf内容如下:upstre ...

  9. portable-net45+win8

    <PropertyGroup> <TargetFramework>netcoreapp1.1</TargetFramework> <RuntimeFramew ...

  10. Dubbo下载-从missing artifactId说起

    项目pom文件引入dubbo 报 missing artifactId https://github.com/dangdangdotcom/dubbox 从GitHub上直接下载解压包, 最好下载分支 ...