本文同步发表于 Prodesire 公众号和 Prodesire 博客。html
Python 的 "is" 和 "==" 想必你们都不陌生,咱们在比较变量和字面量时经常用到它们,但是它们的区别在哪里?什么状况下该用 is
?什么状况下该用 ==
?这成了很多人心中的困惑。python
当咱们判断一个变量是否为 None
时,一般会用 is
:缓存
>>> a = None >>> a is None True >>> b = 1 >>> b is None False
而当咱们判断一个变量是否为字面量(好比某个数值)时,一般会用 ==
:ide
>>> a = 0 >>> a == 0 True >>> a == 1 False
要想解决上面的疑惑,咱们首先须要搞明白 is
和 ==
是什么。code
is
用来检查身份(identity)的同一性,即两个变量是否指向同一个对象。htm
==
用来检查值的相等性(equality),即两个变量的值是否相等。对象
身份的同一性同时也意味值的相等性,既然两个都指向同一个对象,那值就确定相等。可是反之则不是。ci
既然 ==
是用来检查值的相等性,那么两个对象的值比较到底是怎么进行的?字符串
对于基本类型的对象的值比较,咱们很容易理解。好比列表对象 [1, 2, 3] 的值比较就是比较列表的长度和列表中每一个元素的值。get
可是对于自定义的对象,该如何进行值比较?这里就涉及到了 __eq__(self, other)
魔法方法,咱们能够经过该方法来实现对象的 ==
逻辑。好比:
>>> class Foo(object): ... def __eq__(self, other): ... return True ... >>> foo = Foo() >>> foo == 1 True >>> foo == None True >>> foo is None False
在上面的示例中,咱们定义了 Foo
类,并实现了 __eq__(self, other)
方法,它永远返回 True
,也就意味着和任何对象作值比较(==
)结果都是 True
。而当它作同一性比较时,好比和 None
比较,因为不是同一个对象,因此返回 False
。
>>> a = [1, 2, 3] >>> b = a # b 指向 a,a 指向 [1, 2, 3],因此 b 指向同一个 [1, 2, 3] >>> b is a True >>> b == a True
在上述示例中 a
和 b
均指向同一个列表对象 [1, 2, 3]
,因此对它们使用 is
和 ==
,结果都是 True
。
>>> a = [1, 2, 3] >>> b = a[:] # b 复制了一份 a 所指向的列表,产生新的 [1, 2, 3] >>> b is a False >>> b == a True
在上述示例中,因为 b
指向的是 a
的副本,也就是说 a
和 b
指向两个不一样的对象,因此对它们使用 is
的结果是 False
。但因为值相等,使用 ==
的结果就是 True
。
>>> a = 256 >>> b = 256 # 和 a 指向同一字面量 256 >>> a is b # 代表指向同一对象 True >>> a == b True >>> >>> a = 257 >>> b = 257 >>> a == b True >>> a is b # 代表指向不一样对象 False >>>
一般来讲,两个变量指向字面量,它们的比较应该使用 ==
,而非 is
,不然就可能有相似上述示例中的困惑。
在 Python 的交互解释器中,把可能频繁使用的整数对象规定在范围 [-5, 256]
之间,当它们建立好后就会被缓存下来。但凡是须要再用到它们时,就会从缓存中取,而不是从新建立对象。
a
和 b
都指向同一个字面量 256
时,a is b
返回 True
。这是由于声明 b = 256
时,256
整数对象是从缓存中取的,而非从新建立,因此 a
和 b
指向同一个整数对象。a
和 b
都指向同一个字面量 257
时,a is b
返回 False
。这是由于声明 b = 257
时,257
整数对象没被缓存,是从新建立的,因此 a
和 b
指向不一样的整数对象。同理,若是字面量是字符串,结果也相似。
>>> a = 'python.org' >>> b = 'python.org' >>> a is b False >>> a == b True >>> a = 'pythonorg' >>> b = 'pythonorg' >>> a is b True >>> a == b True
is
比较字面量时报 SyntaxWarning鉴于使用 is
比较字面量实际上是不正确的,在 Python 3.8 的 release notes 中,引入以下内容:
> The compiler now produces a SyntaxWarning when identity checks (is and is not) are used with certain types of literals (e.g. strings, numbers). These can often work by accident in CPython, but are not guaranteed by the language spec. The warning advises users to use equality tests (== and !=) instead. (Contributed by Serhiy Storchaka in bpo-34850.)
所以,当咱们使用 is
去比较数字、字符串等字面量时,就会报 SyntaxWarning
:
>>> x = 200 >>> x is 200 Traceback (most recent call last): File "<stdin>", line 1, in <module> SyntaxWarning: "is" with a literal. Did you mean "=="?
说了这么多,其实咱们只须要记住以下两点:
==
。is
。