咨询Python 3.7与旧版本中a is b输出存在差异的原因
为什么Python 3.7中
a is b的结果和旧版本不一样? 这问题太典型了!我当初第一次碰到的时候也懵了好一会儿,本质是Python的**常量驻留(Constant Interning)**机制在3.7版本做了关键调整——简单说就是解释器决定要不要把相同的常量复用成同一个内存对象的规则变了。下面分场景拆解:
1. 整数场景的差异
先看你给出的两个核心例子:
场景1:元组解包赋值
>>> a, b = 257, 257 >>> a is b True # Python < 3.7 False # Python >= 3.7
场景2:单行多变量赋值
>>> a = 257; b = 257; >>> a is b True # 所有Python版本
背后的逻辑:
- 在Python 3.7之前,解释器处理元组解包时,会先把右边的所有字面量做一次驻留,所以
257只会被创建一次,a和b指向同一个内存对象。 - 3.7版本开始,解释器对元组解包的赋值逻辑做了优化:每个字面量会被单独解析,不会共享驻留的对象,所以
a和b是两个完全独立的257对象,is自然返回False。 - 而单行多变量赋值(分号分隔)在所有版本里,都会把同一个字面量驻留复用,所以
a和b始终指向同一个对象。
2. 字符串场景的差异
同样的规则变化也体现在字符串上:
场景1:元组解包赋值
>>> a, b = "wtf!", "wtf!" >>> a is b True # Python < 3.7 False # Python >= 3.7
场景2:字符串重复的长度差异
>>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa' True # 所有Python版本 >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa' False # Python < 3.7 True # Python >= 3.7
背后的逻辑:
- 元组解包的逻辑和整数完全一致:3.7之前会驻留复用同一个字符串,之后会生成独立对象。
- 对于字符串重复的情况,3.7之前解释器只对长度≤20的纯字母/数字/下划线重复字符串做驻留(默认认为短字符串复用价值更高);3.7之后放宽了这个限制,只要是符合规则的重复字符串,不管长度多少都会被驻留,所以21个'a'也会和字面量字符串指向同一个对象。
关键提醒:别用is判断值相等!
这里必须划重点:is是用来判断**对象身份(内存地址)**的,而不是值相等。如果要判断两个变量的值是否相同,永远用==,而不是is。
常量驻留只是Python的一种内存优化手段,不同版本、不同运行环境(比如交互模式和脚本模式)的规则都可能变,依赖is来判断值相等是非常不安全的写法——比如你把a,b=257,257放到脚本文件里运行,哪怕是Python 3.7+,a is b可能又会返回True,因为脚本模式下解释器会做更多常量优化!
内容的提问来源于stack exchange,提问作者SuperKogito
相关产品推荐
相关产品推荐

