<p>布兰登的回答很有启发性,但不正确。实际上有两个问题,一个是
依赖于<code>_CaptureEq</code>作为一个旧样式的类编写的方法(因此,如果您在python3上使用基于散列的容器来尝试它,它将无法正常工作),并且有一个具有您自己的<code>Foo.__eq__</code>定义的配方,当它应该说“我不知道,询问另一个对象是否相等”时,它明确声明两个对象不相等。在</p>
<p>配方问题很容易解决:只需在比较包装器类上定义<code>__hash__</code>:</p>
<pre><code>class _CaptureEq:
'Object wrapper that remembers "other" for successful equality tests.'
def __init__(self, obj):
self.obj = obj
self.match = obj
# If running on Python 3, this will be a new-style class, and
# new-style classes must delegate hash explicitly in order to populate
# the underlying special method slot correctly.
# On Python 2, it will be an old-style class, so the explicit delegation
# isn't needed (__getattr__ will cover it), but it also won't do any harm.
def __hash__(self):
return hash(self.obj)
def __eq__(self, other):
result = (self.obj == other)
if result:
self.match = other
return result
def __getattr__(self, name): # support anything else needed by __contains__
return getattr(self.obj, name)
</code></pre>
<p>您自己的<code>__eq__</code>定义的问题也很容易解决:在适当的时候返回<code>NotImplemented</code>,这样您就不会声称要为与未知对象的比较提供一个明确的答案:</p>
^{pr2}$
<p>通过这两个修复,您将发现Raymond的<code>get_equivalent</code>配方完全可以正常工作:</p>
<pre><code>>>> from capture_eq import *
>>> bar_1 = Bar(1,2,3,4,5)
>>> bar_2 = Bar(1,2,3,10,11)
>>> summary = set((bar_1,))
>>> assert(bar_1 == bar_2)
>>> bar_equiv = get_equivalent(summary, bar_2)
>>> bar_equiv.d
4
>>> bar_equiv.e
5
</code></pre>
<p><strong>更新:</strong>澄清了显式的<code>__hash__</code>重写只是为了正确处理python3的情况。在</p>