在我的代码中,对各种容器(列表,字典等)的相等性进行了大量的比较。容器的键和值的类型为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__
运算符。因此这个新问题。
答案 0 :(得分:9)
改变内置容器检查相等性的方法的唯一途径是使它们包含值,而不是“原始”,包装值(包含在覆盖{{1 }和__eq__
)。如果您需要更改容器本身使用相等性检查的方式,例如出于__ne__
运算符的目的,右侧操作数是一个列表 - 以及容器的方法,例如它们自己的in
(__eq__
是Python的典型方式将在内部执行您编码为type(x).__eq__(y)
)的内容。
如果您正在谈论的是执行您自己的等式检查(没有更改容器本身在内部执行的检查),那么唯一的方法就是更改每个x == y
进入(例如)cont1 == cont2
其中same(cont1, cont2, value_same)
是一个接受两个值的函数,并返回value_same
或True
,如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)来说是完全不可或缺的。如果你通过了那个障碍,那么制造哈希值以某种方式“神奇地”保持一致的噩梦就会产生 - 如果一个词典中的两个实际上不同的键“映射到”这个意义上的“相同”相同在其他字典中键入,那么应该使用两个相应值中的哪一个......?如果你问我这么疯狂就是这样,所以我希望当你说值你做意味着,确切地说,值和不键! - )