我有一组对象,并且对从中获取特定对象感兴趣。经过一番研究,我决定使用这里提供的解决方案:http://code.activestate.com/recipes/499299/
问题是它似乎不起作用。在
我有两个类是这样定义的:
class Foo(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __key(self):
return (self.a, self.b, self.c)
def __eq__(self, other):
return self.__key() == other.__key()
def __hash__(self):
return hash(self.__key())
class Bar(Foo):
def __init__(self, a, b, c, d, e):
self.a = a
self.b = b
self.c = c
self.d = d
self.e = e
注意:这两个类的相等只能在属性a,b,c上定义
http://code.activestate.com/recipes/499299/中的包装器_CaptureEq
也定义了它自己的__eq__
方法。问题是这个方法永远不会被调用(我想)。考虑一下
bar_equiv.d
应该等于4,同样地,bar_equiv .e
应该等于5,但是它们不是。就像我提到的,在执行bar_2 in summary
语句时,__CaptureEq
__eq__
方法没有被调用。在
为什么没有调用__CaptureEq
__eq__
方法?希望这不是一个太模糊的问题。在
问题是
set
比较两个对象的“错误方式”,以便此模式拦截对__eq__()
的调用。2006年的配方显然是针对容器编写的,当被问到是否存在x
时,会检查容器中已经存在的候选y
值:比较,在这种情况下,
^{pr2}$x
上的__eq__()
可以在搜索期间执行特殊操作。但是set
对象的比较方式与此相反:对于集合中的每个y。因此,当您的数据类型是
set
时,此模式在这种形式中可能根本不可用。您可以通过如下方式插入Foo.__eq__()
来确认这一点:然后您将看到一条消息,如:
确认相等性比较对集合中已经存在的对象提出了相等性问题,这是,唉,不是用Hettinger的
_CaptureEq
对象包装的对象。在更新:
我忘了给你一个建议:你想过用字典吗?因为这里有一个密钥的概念,它是对象内部数据的子集,所以您可能会发现,将密钥的概念从对象本身的概念中分离出来,可能会减少尝试这种复杂的对象拦截的需要。只需编写一个新函数,在给定对象和字典的情况下,计算键并在字典中查找,如果存在键,则返回已在字典中的对象,否则在键处插入新对象。在
更新2:好吧,看看这个-尼克的答案在一个方向使用
NotImplemented
,在另一个方向使用NotImplemented
来进行比较。给那家伙几个+1!在布兰登的回答很有启发性,但不正确。实际上有两个问题,一个是 依赖于
_CaptureEq
作为一个旧样式的类编写的方法(因此,如果您在python3上使用基于散列的容器来尝试它,它将无法正常工作),并且有一个具有您自己的Foo.__eq__
定义的配方,当它应该说“我不知道,询问另一个对象是否相等”时,它明确声明两个对象不相等。在配方问题很容易解决:只需在比较包装器类上定义
__hash__
:您自己的
^{pr2}$__eq__
定义的问题也很容易解决:在适当的时候返回NotImplemented
,这样您就不会声称要为与未知对象的比较提供一个明确的答案:通过这两个修复,您将发现Raymond的
get_equivalent
配方完全可以正常工作:更新:澄清了显式的
__hash__
重写只是为了正确处理python3的情况。在这里有两个问题。首先是:
不会做你想做的事。特别是,}。这在Python3中变得更加明显,因为它将向您指出这一点,而不是提供默认的
^{pr2}$t
将永远不会出现在container
中,因为_CaptureEq
没有定义{__hash__
。_CaptureEq
的代码似乎认为,提供一个__getattr__
可以解决这个问题——它不会,因为Python的特殊方法查找不一定会像普通的属性查找一样经过所有相同的步骤——这就是为什么__hash__
(以及其他各种方法)需要在类上定义,并且不能在实例上进行monkeypatch。因此,最直接的方法是定义_CaptureEq.__hash__
,如下所示:但这仍然不能保证有效,因为第二个问题:
set
查找不能保证测试相等性。set
是基于哈希表的,只有在哈希桶中有多个项时才进行相等性测试。您不能(也不想)强制将哈希不同的项放入同一个bucket中,因为这是set
的全部实现细节。首先,最简单的方法是列出:相关问题 更多 >
编程相关推荐