奇怪的是:
>>> a = 123
>>> b = 123
>>> a is b
True
>>> a = 123.
>>> b = 123.
>>> a is b
False
似乎
a is b
或多或少被定义为id(a) == id(b)
。这样很容易出bug:
basename, ext = os.path.splitext(fname)
if ext is '.mp3':
# do something
else:
# do something else
一些 fname 意外地出现在 else 块中。解决方法很简单,我们应该使用
ext == '.mp3'
来代替,但尽管如此,从表面上看 if ext is '.mp3'
似乎是一种很好的 Python 编写方式,而且它比“正确”方式更具可读性。
既然字符串是不可变的,那么它错误的技术细节是什么?什么时候进行身份检查更好,什么时候进行平等检查更好?
它们本质上是不同的。
==
通过调用 __eq__
方法进行比较is
当且仅当两个引用指向同一个对象时才返回 true 与 Java 相比:
is
与对象的 ==
相同==
与对象的 equals
相同据我所知,
is
检查对象身份等价性。由于没有强制的“字符串驻留”,因此恰好序列中具有相同字符的两个字符串通常不是同一个字符串对象。
当您从字符串中提取子字符串(或者实际上是序列中的任何子序列)时,您最终将得到两个包含相同值的不同对象。
因此,当且仅当您比较对象身份时才使用
is
。比较值时使用 ==
。
在 Python 中确定是否使用 is 或 == 的简单规则
这里有一个简单的规则(除非你想了解 Python 解释器的理论或构建框架用 Python 对象做有趣的事情):
仅用于
None
比较。
if foo is None
否则使用==。
if x == 3
那么你就安全了。其基本原理已在上述评论中进行了解释。如果您不能 100% 确定为什么要这样做,请不要使用 is。
定义一个这样的类作为 API 中使用的常量的默认值也很有用。在这种情况下,使用 is 比 == 运算符更正确。
class Sentinel(object):
"""A constant object that does not change even when copied."""
def __deepcopy__(self, memo):
# Always return the same object because this is essentially a constant.
return self
def __copy__(self):
# called via copy.copy(x)
return self
当您将
is
与带有警告(例如 SyntaxWarning: "is" with a literal. Did you mean "=="?
)的文字一起使用时,PyCharm 应该会向您发出警告。因此,在与文字进行比较时,请始终使用 ==
。否则,您可能更喜欢使用 is
来通过对象的引用来比较对象。
我认为这个答案缺少一个明确的例子,说明在比较非
is
的对象时,何时真正使用 None
。
几个物体,例如列表,当分配给其他变量时保留对象引用而不是创建对象的副本。如果没有正确理解,这可能会导致不良行为:
>>> a = [1,2,3]
>>> b = a
>>> a[0] = 0
>>> b
[0,2,3]
>>> b is a
True
>>> b == a
True
但是,如果您创建同一对象的多个实例,它们具有相同的定义,但本质上是不同的对象:
>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a[0] = 0
>>> b
[1,2,3]
>>> b is a
False
>>> b == a
True
说到
None
,那就是特例了。 None
是一个单例对象,因此,None
的实例化仅限于一个对象。因此,使用 None
运算符测试对象是否为 is
总是有效的。
>>> a = None
>>> b = a
>>> b_ = None
>>> a is None
True
>>> b is a
True
>>> b_ is a
True
>>> b_ == a
True
>>> b == None
True
总之,只要你想知道两个变量都指向同一个对象,就使用
is
,也就是说,如果你改变a
的状态,b
也会改变。