一文掌握 Python 中的 "is" 和 "=="

本文同步发表于 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" 和 "==" 是什么

is 用来检查身份(identity)的同一性,即两个变量是否指向同一个对象。htm

== 用来检查值的相等性(equality),即两个变量的值是否相等。对象

身份的同一性同时也意味值的相等性,既然两个都指向同一个对象,那值就确定相等。可是反之则不是。ci

__eq__ 魔法方法

既然 == 是用来检查值的相等性,那么两个对象的值比较到底是怎么进行的?字符串

对于基本类型的对象的值比较,咱们很容易理解。好比列表对象 [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

在上述示例中 ab 均指向同一个列表对象 [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 的副本,也就是说 ab 指向两个不一样的对象,因此对它们使用 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] 之间,当它们建立好后就会被缓存下来。但凡是须要再用到它们时,就会从缓存中取,而不是从新建立对象。

  • ab 都指向同一个字面量 256 时,a is b 返回 True。这是由于声明 b = 256 时,256 整数对象是从缓存中取的,而非从新建立,因此 ab 指向同一个整数对象。
  • ab 都指向同一个字面量 257 时,a is b 返回 False。这是由于声明 b = 257 时,257 整数对象没被缓存,是从新建立的,因此 ab 指向不一样的整数对象。

同理,若是字面量是字符串,结果也相似。

>>> a = 'python.org'
>>> b = 'python.org'
>>> a is b
False
>>> a == b
True
>>> a = 'pythonorg'
>>> b = 'pythonorg'
>>> a is b
True
>>> a == b
True

Python 3.8 引入 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

相关文章
相关标签/搜索