Python中内置类型的自定义比较函数

时间:2013-04-30 18:43:01

标签: python built-in-types

我使用Python的内置集来保存我定义的类的对象。对于本课程,我定义了__eq____ne____hash__,以便我可以通过自定义比较函数比较对象。这很好,直到我发现我实际上需要两个比较函数集,这些函数将在我的代码中的不同时间以不同的方式使用。

我不能在我的类中定义两组__eq__等方法,而Python的内置set类型不接受比较器参数。我想我可以围绕set编写一个包装类,但这似乎比必要的工作要多得多。

有没有比编写我自己的set类更简单的解决方案?

1 个答案:

答案 0 :(得分:9)

假设你有这门课程:

class Thingy(object):
    def __init__(self, key, notkey):
        self.key, self.notkey = key, notkey
    def __eq__(self, other):
        return self.key == other.key
    def __hash__(self):
        return hash(self.key)

现在,您希望将它们放在一个集合中,但需要notkey而不是key。你不能这样做,因为一个集合期望它的元素对于相等具有一致的含义 - 并且对于散列也具有一致的含义,使得a == b总是暗示hash(a) == hash(b)。所以,创建一个包装器:

class WrappedThingy(object):
    def __init__(self, thingy):
        self.thingy = thingy
    def __eq__(self, other):
        return self.thingy.notkey == other.thingy.notkey
    def __hash__(self):
        return hash(self.thingy.notkey)

你可以把那些放在一个集合中:

wts = set(WrappedThingy(thingy) for thingy in thingies)

例如,假设你想要统一你的东西,为每个notkey值保持一个(任意)的东西。只需将它们包起来,将包装纸粘在一套中,然后将它们打开并将未包装的纸粘在列表中:

wts = set(WrappedThingy(thingy) for thingy in thingies)
thingies = [wt.thingy for wt in wts]

这是一种称为“DSU”的更通用的Python模式的一部分。这代表“decorate-sort-undecorate”,现在非常不准确,因为在现代Python中你几乎从不需要它用于排序相关的任务......但是历史上它是有道理的。随意称它为“装饰 - 过程 - 不合理”,希望它能够流行起来,但不要太过希望。

现在你不需要DSU进行排序的原因是大多数排序函数都将key函数作为参数。事实上,即使是无法统一,itertools recipes中的unique_everseen函数也需要key

但是如果你看看它的内幕是什么,它基本上就是DSU:

for element in iterable:
    k = key(element)
    if k not in seen:
        seen.add(k)
        yield element

(事实上它是一个生成器而不是一个列表构建函数意味着它可以“动态地解包”,这使事情变得更简单。但除此之外,同样的想法。)