is 和 == 的区别

相信学过 Python 小伙伴们都知道 is 和 == 都是用来比较 Python 对象的,但是区别就是

  • is 比较需要对象的值和内存地址都相等
  • == 比较只需要对象的值相等就行了

我们来看一个例子

我们可以看到,time 模块的 time() 方法用于获取当前时间,所以 t1 和 t2 的值都是一样的

== 用来判断 t1 和 t2 的值是否相等,所以返回 True

虽然 t1 和 t2 的值相等,但它们是两个不同的对象(每次调用 time() 都返回不同的对象),所以t1 is t2返回 False

那么,如何判断两个对象是否相同呢?

答:判断两个对象的内存地址。如果内存地址相同,说明两个对象使用的是同一块内存,当然就是同一个对象了

我们来看下 t1 和 t2 的内存地址

可以看到它们两个的内存地址是不一样的

小整数池&缓存机制

但是有小伙伴可能会遇到下面的这种情况

咦?怎么 a is b 结果是 True?这应该是两个不同的对象啊

这其实是因为小整数池

python 中经常使用的一些数值定义为小整数池,小整数池的范围是[-5,256]

python 对这些数值已经提前创建好了内存空间,即使多次重新定义也不会再重新开辟新的空间,但是小整数池外的数值在重新定义时都会再次开辟新的空间

所以对于小整数池中的数,内存地址一定是相同的,小整数池中外的数,内存地址是不同的

好,那这次我用小整数池之外的数

?玩我是吧,说好的小整数池中外的数,内存地址是不同的,那上面的代码结果怎么跟说的不一样

上面的代码我是在 IDE 环境下面敲的,我们试着在交互模式下敲

可以看到,在交互模式下,小整数池外的数内存地址不相同,这是为什么呢?

先说结论:这是因为 Python 的缓存机制,所以在 IDE 环境或者脚本模式下同一个整数被多个变量引用不会开辟新的内存空间

Python 缓存机制

  • Python 解释器启动时会先从内存空间中开辟出来一小部分,用于存储高频使用的数据(不可变数据类型),这样可以大大减少高频使用的数据对象创建时申请内存和销毁时撤销内存的开销

  • 在同一代码块下,不可变数据类型的对象(数字,字符串,元祖)被多个变量引用,不会重复开辟内存空间

由上面得知,只有不可变的数据类型(字符串、元祖、基础数据类型)如果被多个变量引用,是不会重复开辟内存空间,但可变数据类型(列表、字典、集合)就除外

  • 可变数据类型

我们来看看

在交互模式下结果也是如此

  • 不可变数据类型

1、小整数池里的数

我们来看下交互模式下的不可变数据类型的缓存机制

可以看到,Python 中整数范围 [-5, 256] 中的数为固定缓存,只要是使用到该范围内的数字,不管是直接赋值还是表达式计算得到的,都会使用固定缓存中的数据

2、非小整数池里的数

对于非小整数池里的数,在 IDE 环境下会使用到缓存,即多个变量引用同一个数据,不会开辟新的内存空间

对于非小整数池里的数,在交互模式下,除非同时赋值或者在同一个局域代码块里面赋值,否则不会使用缓存机制

intern 机制

我们知道,由于 Python 的缓存机制:

  • 不可变的数据类型(字符串、元祖、基础数据类型)如果被多个变量引用,是不会重复开辟内存空间

  • 但可变数据类型(列表、字典、集合)被多个变量引用就会开辟新的内存空间

  • 对于小整数池里的整数,被多个变量引用,不会重复开辟内存空间

但是到目前为止我们知道:在交互模式下,除了特殊情况(同时赋值、同一局域代码块内赋值)以及小整数池之外,所有数据在被多个变量引用时都会开辟新的内存空间

其实还有一种特殊情况,我们来看这么一个例子

看着输出的结果,再跟刚刚所学到的知识做一下对比,是不是发现有不对劲的地方

交互模式下,多个变量引用字符串(不可变数据类型)应该是开辟新的内存空间啊,为啥上面的例子没有开辟

intern机制

字符串类型作为Python中最常用的数据类型之一,Python 为了提高字符串使用的效率和使用性能,使用了 intern(字符串驻留)的技术来提高字符串效率

即值同样的字符串对象仅仅会保存一份,放在一个字符串储蓄池中,是共用的,有新的变量引用同样的字符串的时候,不会开辟新的内存空间,而是引用这个共用的字符串

  • 原理

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

下面是伪代码

1、在交互模式下,只包含字母数字下划线的字符串才会触发 intern 机制

2、在 IDE 环境或者脚本模式下,只要长度不超过20(长度限制),即使使用特殊字符也会触发 intern 机制

PS:我在写这篇文章的时候用的是 python 3.9,发现没有长度限制了,都会触发 intern 机制


感谢阅读,喜欢作者就动动小手[一键三连],这是我写作最大的动力

Python 中 is 和 == 的区别的更多相关文章

  1. python中// 和/有什么区别

    python中// 和/有什么区别 通常C/C++中,"/ " 算术运算符的计算结果是根据参与运算的两边的数据决定的,比如: 6 / 3 = 2 ; 6,3都是整数,那么结果也就是 ...

  2. Python中__repr__和__str__区别

    Python中__repr__和__str__区别 看下面的例子就明白了 class Test(object): def __init__(self, value='hello, world!'): ...

  3. Python中is和==的区别

    Python中有很多运算符,今天我们就来讲讲is和==两种运算符在应用上的本质区别是什么. 在讲is和==这两种运算符区别之前,首先要知道Python中对象包含的三个基本要素,分别是:id(身份标识) ...

  4. python 中is和= = 的区别

    Python中的对象包含三要素:id.type.value,其中id用来唯一标识一个对象,type标识对象的类型,value是对象的值. is判断的是a对象是否就是b对象,是通过id来判断的: ==判 ...

  5. python中 "is"和"=="的区别

    python中"is"和"=="区别 在做leetcode的时候,在判断两个数据是否相等时使用了python中的is not,想着入乡随俗,既然入了python ...

  6. 在python 中is和= = 的区别

    Python中的对象包含三要素:id.type.value其中id用来唯一标识一个对象,type标识对象的类型,value是对象的值is判断的是a对象是否就是b对象,是通过id来判断的==判断的是a对 ...

  7. Python中classmethod与staticmethod区别

    classmethod:类方法staticmethod:静态方法 在python中,静态方法和类方法都是可以通过类对象和类对象实例访问.但是区别是: @classmethod 是一个函数修饰符,它表示 ...

  8. Python笔记:Python中is和==的区别

    ==是比较两端的值 is是比较内存地址: 数据的内存地址可用id()获取 在Python中为了存储数据占用较小的内存,对于int类型和str类型内设了小数据池,其中的数据在被使用时,会使用同一内存地址 ...

  9. Python中各种括号的区别、用途及使用方法

    python语言最常见的括号有三种,分别是:小括号( ).中括号[ ]和大括号也叫做花括号{ }.其作用也各不相同,分别用来代表不同的python基本内置数据类型. python中的小括号( ):代表 ...

  10. 【学习笔记】--- 老男孩学Python,day7 python中is 和 == 的区别 encode decode

    is比较的是id(内存地址)是不是一样,==比较的是值是不是一样 Python中,万物皆对象!万物皆对象!万物皆对象!(很重要,重复3遍) 每个对象包含3个属性,id,type,value id就是对 ...

随机推荐

  1. python——NLP关键词提取

    关键词提取顾名思义就是将一个文档中的内容用几个关键词描述出来,这样这几个关键词就可以提供这个文档的大部分信息,从而提高信息获取效率. 关键词提取方法同样分为有监督和无监督两类,有监督的方法比如构造一个 ...

  2. swift 应用内切换语言

    1:在project info中的locations添加需要的语言 2:创建Localizable.strings文件 点击右边的localization勾选需要的语言 3:创建InfoPlist.s ...

  3. 【flask】建站经验随笔

    [前端] 1.前端table标签中每行使用template中 {%for i in rows%} {% endfor %}来生成之后,如果想对每行进行一个button处理,此时如果使用jquery的$ ...

  4. 线程池使用、countDownLatch、以及数据库批量插入 添加配置优化插入与计算

    //新建线程池ThreadPoolExecutor cpuThreadPoolExecutor = ThreadUtil.getCpuThreadPoolExecutor(); //使用Countdo ...

  5. 字节过滤流 --->对象流(存入对象的)----> ObjectOutputStream: 用法

    前提:1).要有一个类 并创建这个类的对象2)要让类必须继承Serializable接口3)transient修饰的属性 值不参与序列化1创建字节输出节点流FileOutputStream fos = ...

  6. Gridview控件的RowDataBound事件使用中 无法将类型为“System.Web.UI.LiteralControl”的对象强制转换为类型

    无法将类型为"System.Web.UI.LiteralControl"的对象强制转换为类型   使用GridView的时候,相信很多朋友都遇到过"无法将类型为" ...

  7. houdini python 配置 vscode 环境

    一.在我的文档python文件夹中找到houdini.env文件,打开,加入语句 EDITOR = vscode路径 例如:EDITOR = D:\vscode\Microsoft VS Code\C ...

  8. 探究Tomcat

    一.什么是Tomcat? 用来装载javaWeb程序,可以称它为Web容器.是一个运行java的网络服务器,底层是Sochet的一个程序,他也是JSP和Servlet的一个容器. 二.什么要用Tomc ...

  9. 记录下老dropbox的使用

    32-bit: wget -O - "https://www.dropbox.com/download?plat=lnx.x86" | tar xzf - 64-bit: wget ...

  10. [Unity移动端]gradle打包

    建议先看一下这篇文章: https://linxinfa.blog.csdn.net/article/details/118553713?spm=1001.2101.3001.6650.10& ...