前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python中is和==的区别及intern机制

Python中is和==的区别及intern机制

作者头像
啃饼思录
发布2019-11-06 17:21:43
5550
发布2019-11-06 17:21:43
举报

Python中is和==的区别?

说明

好久没更新公众号了,原谅我忘记了。。。

写在前面

嗨小伙伴们好久不见,本来今天是更新一篇关于字符串的文章,但是还没写完,先更新一篇关于is和==区别的文章,因为字符串文章中会涉及到本篇的部分内容。另外最近会勤于更新,大家不要催更了......

is和==的区别

1、is 比较的是地址,注意小整数池和字符串,一般重复创建的时候会指向同一个对象。

代码语言:javascript
复制
t1 = 123t2 = 123print(t1 is t2)  # Trueprint(id(t1), id(t2))  # 1789477024 1789477024print("*********************************")

因为在python中存在intern机制,适用于小整数池和字符串,也就是说创建对象的时候会先在小整数池中查找,如果存在就返回,否则就会新建对象。记住仅仅适用于小整数池和字符串,对于list是不使用的

2、== 比较的是值,其实==重载了对象的__eq__方法,而这个方法比较的是对象的值。

代码语言:javascript
复制
t2 = 123print(t1 == t2)  # Trueprint("*********************************")

因为我们在使用==对两个对象进行值判断的时候,其实就是调用了__eq__这个魔法函数,查看一下str中的__eq__魔法函数:

代码语言:javascript
复制
def __eq__(self, *args, **kwargs):

再来看一下list对象中的__eq__魔法函数:

代码语言:javascript
复制
  def __eq__(self, *args, **kwargs): 
        """ Return self==value. """
        pass

你会发现两者是一模一样,因此==就是对值进行判断,只要值相等就是True。

我们再来看一个例子,在判断类的类别时,是使用is,而不是==,原因在于type(obj)返回的是某个类,而类是一个全局唯一的变量,这种做法可以避免很多未知的错误:

代码语言:javascript
复制
pass
person = Person()if type(person) is Person:  # 记住这里最好使用is,不要使用==

python的intern机制

由于变量的存储机制,python增加了字符串的intern机制,也就是说值同样的字符串对象(整数也适用)仅仅会保存一份,而且是共用的,这也决定了字符串必须是不可变对象,其实仔细想一想,就和数值类型一样,同样的数值仅仅要保存一份即可了,不是必须用不同对象来区分。

我们来看几个例子加深我们的认识,开启Python的IDE,必须使用Python自带的交互式环境,不能使用Pycharm:

代码语言:javascript
复制
>>> a = 'test'>>> b = 'tes' + 't'>>> print(id(a), id(b))>>> print(a is b)# 运行结果:# 51379584 51379584# True

从结果中可以看出它们实际上是同一个对象,所以用is判断就是正确。


intern机制的优点是:在创建新的字符串对象时,会先在缓存池里面找是否有已经存在的值相同的对象(标识符,即只包含数字、字母、下划线的字符),如果有则直接拿过来用(引用),避免频繁的创建和销毁内存,提升效率。

缺点是在拼接字符串时或者在改动字符串时会极大的影响性能。原因是字符串在Python当中是不可变对象,所以对字符串的改动不是inplace(原地)操作,需要新开辟内存地址,即新建对象。这也是为什么拼接字符串的时候不建议用‘+’而是用join()。join()是先计算出全部字符串的长度,然后再一一拷贝,仅仅创建一次对象。


再来看这个例子:

代码语言:javascript
复制
#这里只是演示了包含空格的情况,#实际上除了字母,数字,下划线以外的都是这个情况>>> j = "hello world"  >>> k = "hello world">>> print(id(j), id(k))# 93423920 95800760>>> print(j is k)# False

你可能会好奇怎么是False,因为这里的字符串里面含有空格,导致不会触发intern机制。也就是说字符串中没有空格则会默认开启intern机制,有则就不会开启了。

你现在可能会好奇Python为什么会这么做呢?因为Python的内置函数intern()能显式的对任意字符串进行intern,就说明并不是实现难度的问题,解决这个问题最好是查看Python的源码,可以找到答案,在源代码StringObject.h中的注释能够找到:

代码语言:javascript
复制
/* … … This is generally restricted tostrings that “looklike” Python identifiers, although the intern() builtincan be used to force interning of any string … … */

也就是说intern机制仅仅对那些看起来像是Python标识符的字符串对象才会触发。

我们再来看一个例子:

代码语言:javascript
复制
>>> 'tes'+'t' is 'test'>>> True
>>> a = 'tes'>>> a + 't' is 'test'>>> False

你可能会问为什么是这样?它们不都只是包含字母吗,没有空格应该是被主动intern的呀?的确是不错,但是你忽略了一个事实。在第一个例子中,‘tes’ + ‘t’是在compile-time(编译时)求值的,被替换成了’test’,而在第二个例子中,a + ‘t’是在run-time(运行时)拼接的,导致没有主动触发intern机制。

我们再来看一下Python中的小整数的例子:

代码语言:javascript
复制
>>> a = 257>>> b= 257>>> print(id(a), id(b))94149312 94149488>>> a = 256>>> b = 256>>> print(id(a), id(b))1790200048 1790200048>>> a = -5>>> b = -5>>> print(id(a), id(b))1790195872 1790195872>>> a = -6 >>> b =-6>>> print(id(a), id(b))94148784 94149296

在Python的小整数池[-5,256]这个范围内也是默认开启intern机制,也就是在创建对象的时候会先判断整数是否在小整数池中,是的话就共用同一个对象,否则就新建对象。

总结一下

1、is 比较的是地址,注意小整数池和字符串,一般重复创建的时候会指向同一个对象。 2、== 比较的是值,其实==重载了对象的__eq__方法,而这个方法比较的是对象的值。

3、单词,即Python标识符是不可修改的,默认开启intern机制,是共用对象,当引用计数为0时自动被回收。 4、字符串(包含了除Python标识符以外的字符),不可修改,默认没有开启intern机制,也是当引用计数为0时自动被回收。

5、极少数特殊情况下(如上述最后一个例子时),也不会主动开启intern机制。

6、在Python的小整数池[-5,256]这个范围内也是默认开启intern机制。

后续会更新字符串的文章,请大家等待哈,下篇文章再见~~~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 啃饼思录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在前面
  • is和==的区别
  • python的intern机制
  • 总结一下
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档