内置容器的自定义比较

时间:2010-10-04 23:55:29

标签: python comparison

在我的代码中,对各种容器(列表,字典等)的相等性进行了大量的比较。容器的键和值的类型为float,bool,int和str。内置的==和!=工作得很好。

我刚刚了解到必须使用自定义比较函数比较容器值中使用的浮点数。我已经编写了这个函数(让我们称它为approxEqual(),并假设它需要两个浮点数,如果它们被判断为相等则返回True,否则返回False。)

我更喜欢将现有代码的更改保持在最低限度。 (新的类/函数/等可以根据需要复杂化。)

示例:

if dict1 != dict2:
  raise DataMismatch

需要重写dict1 != dict2条件,以便使用approxEqual函数而不是__eq__来比较dict1和dict2的值中使用的任何浮点数。

字典的实际内容来自各种来源(解析文件,计算等)。

注意:我asked a question earlier关于如何覆盖内置浮动的 eq 。这本来是一个简单的解决方案,但我了解到Python不允许覆盖内置类型的__eq__运算符。因此这个新问题。

1 个答案:

答案 0 :(得分:9)

改变内置容器检查相等性的方法的唯一途径是使它们包含值,而不是“原始”,包装值(包含在覆盖{{1 }和__eq__)。如果您需要更改容器本身使用相等性检查的方式,例如出于__ne__运算符的目的,右侧操作数是一个列表 - 以及容器的方法,例如它们自己的in__eq__是Python的典型方式将在内部执行您编码为type(x).__eq__(y))的内容。

如果您正在谈论的是执行您自己的等式检查(没有更改容器本身在内部执行的检查),那么唯一的方法就是更改每个x == y进入(例如)cont1 == cont2其中same(cont1, cont2, value_same)是一个接受两个值的函数,并返回value_sameTrue,如False。这可能是太具侵略性的WRT你指定的标准。

如果您可以自己更改容器(即,创建容器对象的位置数远远小于检查两个容器是否相等的位置数),那么使用容器覆盖==的子类是最好的。

E.g:

__eq__

class EqMixin(object): def __eq__(self, other): return same(cont1, cont2, value_same) 正如我在A的第2段中提到的那样)和

same

(对于您需要的其他容器类型等),然后在任何地方(例如)

class EqM_list(EqMixin, list): pass

将其更改为

x = list(someiter)

并确保还捕获其他方法来创建列表对象,例如取代

x = EqM_list(someiter)

x = [bah*2 for bah in buh]

x = EqM_list(bah*2 for bah in buh)

x = d.keys()

等等。

是的,我知道,这是多么麻烦 - 但这是Python的核心原则(和实践;-)内置类型(无论是容器,还是像x = EqM_list(d.iterkeys()) 这样的值类型)本身不能改变。这是一个非常不同的哲学,例如, Ruby和Javascript(我个人更喜欢它,但我确实看到它有时似乎有限制!)。

修改:OP特定请求似乎(就此回答而言)“如何为各种容器类型实现float”,而不是如何应用它而不更改same进入函数调用。如果这是正确的,那么(例如)为了简单起见不使用迭代器:

==

请注意,这适用于,根据要求,。 “模糊”dict键(或集合成员)的相等比较是 REAL 问题。以这种方式看待它:首先,如何绝对肯定地保证 def samelist(a, b, samevalue): if len(a) != len(b): return False return all(samevalue(x, y) for x, y in zip(a, b)) def samedict(a, b, samevalue): if set(a) != set(b): return False return all(samevalue(a[x], b[x]) for x in a)) 完全暗示并确保samevalue(a, b) and samevalue(b, c)?这种传递性条件不适用于我见过的大多数半合理的“模糊比较”,但它对于基于散列表的容器(例如dicts和sets)来说是完全不可或缺的。如果你通过了那个障碍,那么制造哈希值以某种方式“神奇地”保持一致的噩梦就会产生 - 如果一个词典中的两个实际上不同的键“映射到”这个意义上的“相同”相同在其他字典中键入,那么应该使用两个相应值中的哪一个......?如果你问我这么疯狂就是这样,所以我希望当你说意味着,确切地说,键! - )