代码之家  ›  专栏  ›  技术社区  ›  max

内置容器的自定义比较

  •  5
  • max  · 技术社区  · 14 年前

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

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

    我希望对现有代码的更改保持在最低限度。(新的类/函数/等可以根据需要变得复杂。)

    例子:

    if dict1 != dict2:
      raise DataMismatch
    

    这个 dict1 != dict2 需要重写条件,以便使用approxequal函数而不是 __eq__ .

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

    注:I asked a question earlier 关于如何重写内置float的 情商 . 这本来是一个简单的解决方案,但我了解到python不允许重写内置类型' 爱斯克 操作员。因此这个新问题。

    1 回复  |  直到 14 年前
        1
  •  9
  •   Alex Martelli    14 年前

    更改内置容器检查相等性的方式的唯一途径是使其包含为值,而不是“原始”, 包裹 值(包装在重写的类中 __eq__ __ne__ )如果您需要更改容器本身使用相等检查的方式,例如为了 in 运算符,其中右侧操作数是列表以及容器的方法(如它们自己的方法)中的操作数 爱斯克 ( type(x).__eq__(y) python在内部执行代码的典型方式是 x == y )

    如果你说的是表演 你自己 相等性检查( 没有 更改容器本身在内部执行的检查),然后唯一的方法是更改 cont1 == cont2 进入(例如) same(cont1, cont2, value_same) 在哪里? value_same 函数接受两个值并返回 True False 喜欢 == 会。这可能太有侵略性了,按照您指定的标准。

    如果你能改变 容器本身 (即,创建容器对象的位置数比检查两个容器是否相等的位置数小得多),然后使用覆盖的容器子类 爱斯克 是最好的。

    例如。:

    class EqMixin(object):
      def __eq__(self, other):
        return same(cont1, cont2, value_same)
    

    same 正如我在A的第2段中提到的那样)和

    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()
    

    具有

    x = EqM_list(d.iterkeys())
    

    诸如此类。

    是的,我知道,这有点麻烦——但构建类型(无论是容器类型,还是像这样的值类型)是Python的一个核心原则(和实践;-)。 float 自己 不能 被改变。这与Ruby和Javascript的哲学是截然不同的(我个人更喜欢它,但我知道它有时似乎是有限制的!).

    编辑 :操作特定的请求似乎是(就这个答案而言)“如何实现 相同的 “对于各种容器类型,在不更改 = 进入函数调用。如果这是正确的,那么(例如)为了简单起见,不使用迭代器:

    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) 完全暗示并确保 samevalue(a, c) ?这种可传递性条件不适用于我所见过的大多数半敏感的“模糊比较”,但是它对于基于哈希表的容器(如dict和set)来说是完全必要的。如果您通过了这个障碍,那么以某种方式使哈希值“神奇地”一致的噩梦就出现了——如果在一个dict“map to”中有两个实际上不同的键在这个意义上与 相同的 键入另一个dict,那么应该使用两个对应的值中的哪一个…?如果你问我的话,这种疯狂是谎言,所以我希望当你说 价值观 确切地说, 价值观 钥匙!-)