Python比较原始类型时is与==运算符的差异及原理解析
先搞懂最基础的前提
首先别拿JS的原始类型/引用类型那套逻辑套Python——Python里没有原始类型,不管是整数、字符串、布尔值还是None,全都是一等对象,每个值都有自己的内存地址、自己的方法,不存在“原始值存在栈上、对象存在堆上”的区分。
两个比较运算符的边界从设计上就完全划清了:
==只判断值是否相等,底层调用对象的__eq__方法做内容比对,不关心两个值是不是同一个内存实例is只判断对象身份,本质就是对比两个变量指向的内存地址是否一致,等价于id(a) == id(b),完全不关心内容是不是一样
为什么大家都写<something> is not None
因为None是Python解释器启动时就创建好的全局单例,整个程序运行周期里内存里永远只有一个None实例,不存在“内容和None相等但不是同一个对象”的情况。
用is判断None是最严谨、性能最高的写法:如果用== None做判断,万一被判断的对象自定义了__eq__方法,刻意让自己和None比对时返回True,就会出现误判,is完全不会有这个问题——它根本不跑对象的自定义比对逻辑,直接查内存地址,结果100%准确。
你测试的字符串比对结果差异原因
你看到的a is b为True、x is y为False,本质是Python的字符串驻留优化机制,这是解释器的实现细节,不是语法层面的强制规则:
- 代码里直接写死的、符合标识符规则(仅含字母、数字、下划线,长度较短)的字符串字面量,会在代码编译阶段被加入全局字符串驻留池,相同内容的这类字面量全程只会存一份,所有赋值这类字面量的变量,都会指向同一个内存对象。你代码里直接写的
a = 'abc'、b = 'abc',编译完成后两个变量本来就指向同一个提前创建好的'abc'实例,所以a is b返回True。 - 而
''.join(['a','b','c'])的结果是代码运行到这一行时才动态拼接生成的新字符串,默认不会自动加入驻留池,哪怕内容和驻留池里的'abc'完全一样,它也是一块新分配内存的独立对象,和x指向的驻留池字符串地址不一样,所以x is y返回False。
重要提醒:字符串驻留、小整数缓存(比如-5到256之间的整数默认会被缓存,相同值指向同一个对象)全都是解释器做的性能优化,不同版本、不同运行场景下的缓存规则可能变,绝对不要在业务代码里用is判断字符串、整数这类值的内容是否相等,is唯一稳定可靠的通用使用场景,就是判断对象是不是None这类全局单例。
对应你写的测试代码,结果逻辑完全对应:
a = 'abc' b = 'abc' print( a == b) # True,两个字符串内容完全一致 print( a is b) # True,两个变量指向编译期驻留的同一个'abc'对象 x = 'abc' y = ''.join(['a', 'b', 'c']) print( x == y ) # True,拼接生成的字符串内容和x完全相同 print( x is y ) # False,y是运行时新创建的独立对象,内存地址和x不同
内容的提问来源于stack exchange,提问作者Pall Arpad
相关产品推荐
相关产品推荐

