==
是一个相等性测试。它检查左右两侧是否是相等的对象(根据它们的 __eq__
或 __cmp__
方法)。
is
是一个身份测试。它检查左右两侧是否是同一个对象。不进行方法调用,对象不能影响 is
操作。
你可以使用 is
(和 is not
)来检查单例对象,例如 None
,这样你就不需要关心那些想要假装成 None
的对象,或者你想保护对象不因为与 None
进行比较而出现问题。
None
几乎没有任何方法和属性。如果您的__eq__
测试期望一个方法或属性,它可能会出错。例如,如果other
恰好是None
,那么def __eq__(self, other): return self.size == other.size
就会出错。 - S.Lottis
就像 Java 的 ==
,Python 的 ==
就像 Java 的 .equals()
。当然,这只对了解 Java 的人有用。 - Tyleris
就像 ===
(非常相等),反之 is not
就像 !==
(不完全相等)。 - Orwellophile首先,让我解释一些术语。如果你只想得到问题的答案,请向下滚动到“回答您的问题”。
对象标识:当你创建一个对象时,你可以将它赋值给一个变量。然后你也可以将它赋值给另一个变量。再接着另一个。
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
在这种情况下,cancel
、close
和dismiss
都指向内存中的同一对象。你只创建了一个Button
对象,三个变量都指向这个对象。我们说cancel
、close
和dismiss
都引用了相同的对象;也就是说,它们引用同一个对象。
对象相等性:当你比较两个对象时,通常不关心它是否引用内存中的完全相同对象。通过对象相等性,你可以定义自己的规则来比较两个对象。当你写if a == b:
时,实际上是在说if a.__eq__(b):
。这让你可以在a
上定义一个__eq__
方法,以便使用自己的比较逻辑。
基本原理:两个对象具有相同的数据,但不是同一个对象。(它们在内存中不是同一个对象。) 例子:字符串
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
注意:在这里我使用unicode字符串,因为Python足够聪明,可以重用常规字符串而不会在内存中创建新的字符串。
这里有两个unicode字符串a
和b
,它们具有完全相同的内容,但它们在内存中不是同一个对象。然而,当我们进行比较时,我们希望它们被视为相等。实际上是unicode对象已经实现了__eq__
方法。
class unicode(object):
# ...
def __eq__(self, other):
if len(self) != len(other):
return False
for i, j in zip(self, other):
if i != j:
return False
return True
注意:unicode
上的 __eq__
可以比这个实现更高效。
原因:如果一些关键数据相同,两个对象具有不同的数据,但被视为相同的对象。示例:大多数类型的模型数据。
>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True
我这里有两个戴尔显示器,a
和 b
。它们的型号和制造商都相同,但数据不同且在内存中也不是同一个对象。然而,当我们比较它们时,希望它们相等。这里使用了 Monitor 对象实现的 __eq__
方法。
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
与 None
比较时,总是使用 is not
。在 Python 中,None
是一个单例 - 内存中只有一个实例。
通过比较 标识,可以非常快地执行此操作。Python 检查您引用的对象是否具有与全局 None 对象相同的内存地址 - 这是两个数字之间非常快速的比较。
通过比较 相等性,Python 必须查找您的对象是否具有 __eq__
方法。如果没有,则检查每个超类是否有 __eq__
方法。如果找到了,则调用它。如果 __eq__
方法很慢,并且在注意到另一个对象为 None
时不立即返回,则情况尤其糟糕。
没有实现 __eq__
吗?那么 Python 可能会在 object
上找到 __eq__
方法并使用它 - 它只检查对象标识。
在 Python 中比较大多数其他东西时,您将使用 !=
。
请考虑以下内容:
class Bad(object):
def __eq__(self, other):
return True
c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)
None
是一个单例对象,因此身份比较始终有效,而一个对象可以通过 .__eq__()
模拟等式比较。
None
相等的原因,但是针对其他类型实现相等性可能会导致关于None
的不正确行为作为副作用发生。这并不是安全方面的问题,而更多地是正确性方面的问题。 - Ignacio Vazquez-Abrams()
和1
并非天生单例。 - Mike Graham-NSMALLNEGINTS <= n <= NSMALLPOSINTS
)和空元组是单例。事实上,这并没有被记录或保证,但它不太可能改变。 - ephemient