python字符串常量有什么区别_Python经典面试题:is与==的区别

is用于判断两个对象是否为同一个对象,具体来说是两个对象在内存中的位置是否相同。

python为了提高效率,节省内存,在实现上大量使用了缓冲池技术和字符串intern技术。

整数和字符串是不可变对象,也就意味着可以用来共享,如100个“python”字串变量可以共享一个“python”字符串对象,而不是创建100个“python”字符串。

一、小整数对象池

为了应对小整数的频繁使用,python使用对小整数进行了缓存,默认范围为[-5,256],在这个范围内的所有整数被python完全地缓存,当有变量使用这些小整数时,增加对应小整数对象的引用即可。afd1a1dc2858bf99abb17480b55a4430.png

由上面的实例可以看到,当变量在[-5,256]之间时,两个值相同的变量事实上会引用到同一个小整数对象上,也就是小整数对象池中的对象,而不会去创建两个对象。而当变量超出了这个范围,两个值相同的变量也会各自创建整数对象,所以两者对应的对象不同。

二、字符串intern

如果当前变量引用的字符串对象已经存在的话,直接增加对应字符串对象的引用,而不去创建新的字符串对象,这就是字符串intern机制。

说白了,intern机制就是每创建一个比较短的字符串对象,就在一个叫interned的字典里面查看是否存在字符串相同的字符串对象,如果存在的话,就把字典存放的对象的ob_refcnt加1,然后销毁新创建的对象,所以才会出现下面的情景 a is b的结果为True:114bf5fe4a683396a500cf5129a2b90d.png

1. 奇怪的现象

在详细探讨字符串intern机制之前,先看一个奇怪的问题:

直接在交互式IPython中运行:3ef974842236bc90e5dafbf8277bbb5a.png

i is j的结果是False。

定义一个函数并运行:b279260cd4cf77700f6e1d4acb23b53c.png

输出结果:

True

上述代码分开运行,结果为False,但是合在一起结果却为True。也就是说分开运行的时候,i和j指向不同对象,而合在一起的时候i,j却指向了相同对象。为了明白其中的缘由,需要简单理解python的编译机制。

三、编译机制

在python中,万物皆对象,包括代码本身也是一种对象。python用code对象表示代码,代码编译后产生code对象。通常一个作用域对应一个code对象。54bfc5516ee9eb7f909779258bf83164.png

1. 编译结果42004da23ab6013c5d94918df039401e.png

上述代码中编译生成了两个code对象,一个代表全局作用域,另一个代表函数f。

code对象保存了变量,常量(常量字面量)以及编译结果。code对象用常量表来保存常量,考虑到一个常量可能出现多次,在一张表上保存一个常量多次太过于奢侈。所以code对象对每个常量只保存一次,在需要引用它的地方使用它在常量表的位置作为常量的表示。在上述编译结果中可以看到,"1 2"这个字符串常量使用了两次,编译的代码为"LOAD_CONST 0",这里的0就是"1 2"在常量表当中的位置。

由于编译的这个特性,在同一个code对象 中的变量,如果它们引用了同一个常量,那么无论这个常量有没有缓冲机制,它们引用的都是同一个对象。6f232aa9f51736d1f7bcb8bfbfc37412.png

2. 案例理解99d9e32e4f6c8976a12b0d28f34a0c2d.png

输出结果:

True True True True

字符串对象除了intern机制以外,还有类似于小整数对象的字符缓冲池,其实就是用一个类似于数组的东西(characters array)指向这个对象,对只有一个字符的字符串,第一次创建时候会进行如下操作:

1.创建对象

2.对其进行intern操作

3.将对象放进字符缓冲池bc3461a8642fda8ea87f2ac7a83f27b8.png

那么下次再创建这个字符对象时候,会首先查看字符缓冲池中是否存在这个对象,如果存在的话,返回这个缓冲对象。区别于小整数对象的是,小整数对象在python解释器初始化之初就创建了,而字符串缓冲池指向的对象直到用到的时候才会创建。

四、编译机制与小整数对象池对比2bce5a560a00bc72e825b9bbe7f49b1f.png

i和j引用同一个常量,这是编译机制,所以i与j指向同一个整数对象,后面a和b虽然相等,但不引用常量,此时启用小整数对象池,a和b都等于256,在对象池中,所以a,b引用同一个对象,后面c和d不在对象池中,所以两者对象不同。

这里有一点需要注意,没有变量参与的运算会被编译器直接优化成对应的常量,进而保存进常量表中。

五、字符串intern机制与字符缓冲池

在编译过程中,字符串intern机制将所有的变量名进行intern,但对常量进行的intern有一点特殊的限制。能够intern的常量必须只包含[a-zA-Z0-9_],即字母数字加下划线,如果含有其他字符,就不会intern。在运行过程中,通过计算得到的字符串不会intern。

字符串有一个和小整数对象池相似的字符缓冲池,用于在运行过程中缓存单个字符,所以计算得到的字符串虽然不会intern,但如果是单个字符,就会使用到字符缓冲池。78038ab3595d390ed6483e3b1a7934df.png

可以看到,a和b确实指向同一个对象,而c和d指向不同对象,这就是字符缓冲池。

1dd34ce6bfa6a1b19e5c13cde1975244.png

六、编译机制与字符串intern对比c28c4b9ada1f6941a4115b599ecbc7a1.png

i包含空格,包含空格的常量不会被intern,而其他两个常量不包含其他字符,所以会被intern。

七、总结python代码被编译成code对象,通常一个code对象对应于一个作用域,作用域中重复出现的变量名以及常量在code中只保存一次。

字符串intern机制主要作用于编译过程,在编译收集完变量和常量时,对变量和常量进行intern,而后构建一个code对象。

字符串intern对常量的intern有限制,能够intern的常量必须只包含[a-zA-Z0-9_],即字母数字加下划线,如果含有其他字符,就不会intern。

小整数对象池和字符缓冲池都是作用于运行过程中,python缓存小的整数和字符,当有变量使用这些对象时,不用额外创建对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值