与==比较时,具有相同id的对象是否总是相等的?
Are objects with the same id always equal when comparing them with ==?
如果我有两个对象 o1 和 o2,我们知道
id(o1) == id(o2)
returns 真.
那么,是否遵循
o1 == o2
或者情况并非总是如此?我正在研究的论文说情况并非如此,但在我看来它应该是真的!
这篇论文是对的。考虑以下因素。
class WeirdEquals:
def __eq__(self, other):
return False
w = WeirdEquals()
print("id(w) == id(w)", id(w) == id(w))
print("w == w", w == w)
输出是这样的:
id(w) == id(w) True
w == w False
id(o1) == id(o2)
并不意味着 o1 == o2
。
让我们看一下这个 Troll
,它将 __eq__
覆盖为始终 return False
。
>>> class Troll(object):
... def __eq__(self, other):
... return False
...
>>> a = Troll()
>>> b = a
>>> id(a) == id(b)
True
>>> a == b
False
也就是说,在标准库中应该有 非常 几个 object-ids 匹配但 __eq__
可以 return False
无论如何,感谢@MarkMüller 找到了一个很好的例子。
所以要么对象是疯狂的、非常特殊的(比如 nan),要么是并发问题困扰着你。考虑这个极端的例子,其中 Foo
有一个更合理的 __eq__
方法('forgets' 检查 ids)并且 f is f
总是 True
。
import threading
class Foo(object):
def __init__(self):
self.x = 1
def __eq__(self, other):
return isinstance(other, Foo) and self.x == other.x
f = Foo()
class MutateThread(threading.Thread):
def run(self):
while True:
f.x = 2
f.x = 1
class CheckThread(threading.Thread):
def run(self):
i = 1
while True:
if not (f == f):
print 'loop {0}: f != f'.format(i)
i += 1
MutateThread().start()
CheckThread().start()
输出:
$ python eqtest.py
loop 520617: f != f
loop 1556675: f != f
loop 1714709: f != f
loop 2436222: f != f
loop 3210760: f != f
loop 3772996: f != f
loop 5610559: f != f
loop 6065230: f != f
loop 6287500: f != f
...
不总是:
>>> nan = float('nan')
>>> nan is nan
True
或按照问题中的相同方式表述:
>>> id(nan) == id(nan)
True
但是
>>> nan == nan
False
NaN is a strange thing. Per definition it is not equal nor less or greater than itself. But it is the same object. More details why all comparisons have to return False
in this SO question.
如果我有两个对象 o1 和 o2,我们知道
id(o1) == id(o2)
returns 真.
那么,是否遵循
o1 == o2
或者情况并非总是如此?我正在研究的论文说情况并非如此,但在我看来它应该是真的!
这篇论文是对的。考虑以下因素。
class WeirdEquals:
def __eq__(self, other):
return False
w = WeirdEquals()
print("id(w) == id(w)", id(w) == id(w))
print("w == w", w == w)
输出是这样的:
id(w) == id(w) True
w == w False
id(o1) == id(o2)
并不意味着 o1 == o2
。
让我们看一下这个 Troll
,它将 __eq__
覆盖为始终 return False
。
>>> class Troll(object):
... def __eq__(self, other):
... return False
...
>>> a = Troll()
>>> b = a
>>> id(a) == id(b)
True
>>> a == b
False
也就是说,在标准库中应该有 非常 几个 object-ids 匹配但 __eq__
可以 return False
无论如何,感谢@MarkMüller 找到了一个很好的例子。
所以要么对象是疯狂的、非常特殊的(比如 nan),要么是并发问题困扰着你。考虑这个极端的例子,其中 Foo
有一个更合理的 __eq__
方法('forgets' 检查 ids)并且 f is f
总是 True
。
import threading
class Foo(object):
def __init__(self):
self.x = 1
def __eq__(self, other):
return isinstance(other, Foo) and self.x == other.x
f = Foo()
class MutateThread(threading.Thread):
def run(self):
while True:
f.x = 2
f.x = 1
class CheckThread(threading.Thread):
def run(self):
i = 1
while True:
if not (f == f):
print 'loop {0}: f != f'.format(i)
i += 1
MutateThread().start()
CheckThread().start()
输出:
$ python eqtest.py
loop 520617: f != f
loop 1556675: f != f
loop 1714709: f != f
loop 2436222: f != f
loop 3210760: f != f
loop 3772996: f != f
loop 5610559: f != f
loop 6065230: f != f
loop 6287500: f != f
...
不总是:
>>> nan = float('nan')
>>> nan is nan
True
或按照问题中的相同方式表述:
>>> id(nan) == id(nan)
True
但是
>>> nan == nan
False
NaN is a strange thing. Per definition it is not equal nor less or greater than itself. But it is the same object. More details why all comparisons have to return False
in this SO question.