在Python中何时使用'is'关键字?
今天我学习了Python中的is
关键字,并尝试了以下内容:
>>> x=2+2
>>> y=4
>>> x is y
True
我一开始用整数来测试is
,因为我知道结果应该是False
,所以结果让我感到很惊讶!为了给大家一些背景,我之前的编程经验主要是C++和C#,在那两种语言中,值类型和对象类型是有区别的。而在Python中,我现在意识到,所有东西都是引用类型。
看起来x is y
返回True
的原因和这个问题中解释的一样,Python中的'is'关键字是如何实现的?,这和用is
比较字符串有关。也就是说,运行时环境通过共享或“驻留”整数来节省内存,就像它对待字符串一样——这个在另一个问题的回答中有更详细的解释:Python的“is”运算符在处理整数时表现得很意外,这是我在最初发帖后发现的。
我还发现另一个令人惊讶的事情是,is
返回的值是依赖于实现的。这和我主要的问题有关。在关于is
在字符串方面实现的参考问题中,有一些讨论关于何时使用is
,有几个用户表示他们几乎从不使用它。所以我的问题是,什么时候应该使用is
关键字?有没有一些经典的例子或一般的规则?
3 个回答
首先,x 是 y 为 True 的原因和这个问题中解释的内容一样吗?这个问题是关于在 Python 中如何使用 'is' 关键字,特别是与字符串相关的。
其实是有点相似的。在 Python 中,整数范围从 -5
到 256
的这些数字是被缓存的。这是为了提高性能。
那么我的问题是,什么时候应该使用 is 这个关键字呢?
你可以用 is
来检查两个引用是否指向同一个对象(它检查的是对象的身份)。另外,当你要把一个对象的引用和 None
进行比较时,推荐使用 is
:
if some_object is None:
# ...
“is
是用来检查身份的,不是用来检查相等的。这意味着 Python 只是比较对象所在的内存地址。”
有一个简单的规则可以帮助你判断什么时候用 ==,什么时候用 is。
==
是用来检查值是否相等的。当你想知道两个对象的值是否相同时,就用它。is
是用来检查引用是否相等的。当你想知道两个引用是否指向同一个对象时,就用它。
一般来说,当你比较某个简单类型时,通常是在检查值是否相等,所以你应该使用 ==。
如果两个变量指向同一个对象,is
会返回 True;如果变量指向的对象值相等,==
会返回 True。
>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
>>> b == a
True
>>> b = a[:]
>>> b is a
False
>>> b == a
True
第二个测试之所以有效,是因为 Python 会缓存小整数对象,这属于实现细节。对于较大的整数,这种方法就不管用了:
>>> 1000 is 10**3
False
>>> 1000 == 10**3
True
The same holds true for string literals:
>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True
注意: “由于自动垃圾回收、空闲列表和描述符的动态特性,你可能会在某些使用 is 操作符的情况下看到看似不寻常的行为,比如涉及实例方法或常量的比较。”
由于 CPython 的引用实现方式,如果你错误地使用 is 来比较整数的引用相等性,你会得到意想不到和不一致的结果:
>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False
这基本上符合我们的预期:a 和 b 的值相同,但它们是不同的实体。那么这个呢?
>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True
这与之前的结果不一致。发生了什么?原来 Python 的引用实现会将范围在 -5 到 256 之间的整数对象缓存为单例实例,以提高性能。这里有个示例来演示这一点:
>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
...
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False
这也是不应该使用 is 的另一个明显原因:当你错误地将其用于值相等性时,行为会依赖于具体的实现。
当你想知道两个对象是否是同一个对象时,应该使用 is
。如果你只是想知道两个对象的值是否相同,就不要用它。
有一个经典的例子,但这个例子其实帮助不大。人们会告诉你,检查 None
值时应该用 x is None
,而不是 x == None
。不过,这两者之间实际上差别不大。(想了解更多,可以查看这个问题。)
在某些情况下,你可能会创建一些值相同但却是不同对象的东西。比如,你可以想象一个幻想战争游戏,玩家可以魔法般地创造小兵来与对手作战。于是,玩家可能会创造100个一模一样的兽人。每个兽人可以用一个对象来表示,它们在属性上是相同的,但实际上是100个不同的对象。现在,如果对手试图对其中一个兽人施放“火球”法术,而玩家在同一回合对另一个兽人施放“防火”法术,你可能想检查火球法术的目标是否 is
防护法术的目标。因为所有的兽人都是相等的,仅仅用相等的方式检查是不够的,只有特定的一个兽人才是每个法术的目标,而你想知道这两个目标是否是同一个对象。这个例子虽然有点牵强,但可以让你大致明白在什么情况下你可能会用到 is
。