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

Ell*_*ter 5 python built-in-types

我使用Python的内置集来保存我定义的类的对象.对于这个类,我定义的__eq__,__ne____hash__这样我可以通过我的定义比较功能比较的对象.这工作得很好,直到我发现我确实需要2套对比功能,这将在不同的方式在不同的时间在我的代码中使用.

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

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

aba*_*ert 10

假设你有这门课程:

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)
Run Code Online (Sandbox Code Playgroud)

现在,你想把它们放在一个集合中,但是键入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)
Run Code Online (Sandbox Code Playgroud)

你可以把它们放在一套:

wts = set(WrappedThingy(thingy) for thingy in thingies)
Run Code Online (Sandbox Code Playgroud)

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

wts = set(WrappedThingy(thingy) for thingy in thingies)
thingies = [wt.thingy for wt in wts]
Run Code Online (Sandbox Code Playgroud)

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

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

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

for element in iterable:
    k = key(element)
    if k not in seen:
        seen.add(k)
        yield element
Run Code Online (Sandbox Code Playgroud)

(它是一个生成器而不是列表构建函数的事实意味着它可以"动态地进行未装饰",这使得事情变得更简单.但是,否则,同样的想法.)