在Python中==和Is有区别吗?
是的,它们有一个非常重要的区别。
==: check for equal——语义是等价的对象(不一定是同一个对象)将被测试为相等。如文档所述:
运算符<、>、==、>=、<=和!=比较两个对象的值。
Is:检查身份——语义是对象(在内存中)是对象。同样,文档说:
操作符is和is not测试对象的同一性:x是y是真
当且仅当x和y是同一个对象。对象恒等式是
使用id()函数确定。X不是y会得到逆函数
真值。
因此,检查标识符与检查对象的id是否相等是一样的。也就是说,
a is b
等于:
id(a) == id(b)
其中id是内建函数,返回一个“在同时存在的对象中保证唯一”的整数(参见help(id)),其中a和b是任意对象。
其他使用说明
您应该使用这些语义比较。用is检查身份,用==检查是否相等。
一般来说,我们用is来检查恒等式。当我们检查一个在内存中只存在一次的对象时,这通常是有用的,在文档中称为“单例”。
is的用例包括:
没有一个
enum值(当使用enum模块中的Enums时)
通常模块
通常是类定义产生的类对象
通常是由函数定义产生的函数对象
任何其他在内存中只存在一次的对象(通常都是单例对象)
一个你想要的特定对象
==的常用用例包括:
数字,包括整数
字符串
列表
集
字典
自定义可变对象
其他内建的不可变对象,在大多数情况下
同样,对于==,一般的用例是,你想要的对象可能不是同一个对象,相反,它可能是一个等价的对象
PEP 8说明
标准库的官方Python风格指南PEP 8也提到了is的两个用例:
与像None这样的单例对象的比较应该总是使用is或
不是,不是相等运算符。
另外,当你真正的意思是如果x不是None时,要注意写if x
例如,当测试一个变量或参数是否默认为None时
被设置为其他值。另一个值可能具有类型(例如
作为容器),在布尔上下文中可能是假的!
由同一推断相等
如果is为真,通常可以推断相等性-逻辑上,如果一个对象是自身,那么它应该测试为等效于自身。
在大多数情况下,这个逻辑是正确的,但它依赖于__eq__特殊方法的实现。正如医生所说,
相等性比较(==和!=)的默认行为是基于
对象的身份。因此,实例的相等性比较
具有相同的同一性结果就等于相等,而相等的比较
具有不同身份的实例会导致不平等。一个
这种默认行为的动机是所有对象的愿望
应该是自反的(即x是y意味着x == y)。
为了保持一致性,建议:
平等比较应该是自反性的。换句话说,完全相同
对象的比较应该相等:
X是y意味着X == y
我们可以看到这是自定义对象的默认行为:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
反证法通常也是正确的——如果某物测试为不相等,你通常可以推断出它们不是同一个物体。
由于相等性测试可以自定义,因此这种推断并不总是适用于所有类型。
一个例外
一个值得注意的例外是nan——它总是被测试为不等于自身:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
检查身份比检查相等性要快得多(相等性可能需要递归地检查成员)。
但它不能代替相等,因为你可能会发现多个对象是相等的。
注意,比较列表和元组的相等性将假定对象的身份相等(因为这是一个快速检查)。如果逻辑不一致,就会产生矛盾——就像nan一样:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
一个警世故事:
问题是要比较整数。您不应该假定一个整数的实例与另一个引用获得的实例是相同的实例。下面这个故事解释了原因。
一位评论者的代码依赖于小整数(-5到256)在Python中是单例,而不是检查是否相等。
哇,这可能会导致一些潜伏的bug。我写了一些代码来检查a是不是b,这就像我想要的那样,因为a和b通常都是很小的数字。这个错误直到今天才出现,因为a和b终于大到不能被缓存了。——gwg
它在开发过程中发挥了作用。它可能通过了一些单元测试。
它在生产中工作-直到代码检查大于256的整数,在这一点上它在生产中失败了。
这是一个生产失败,可以在代码检查或样式检查器中发现。
让我强调一下:不要使用is来比较整数。