Python中内置类型的自定义比较功能 [英] Custom comparison functions for built-in types in Python

查看:172
本文介绍了Python中内置类型的自定义比较功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using Python's built-in sets to hold objects of a class I have defined. For this class, I defined __eq__, __ne__, and __hash__ so that I can compare objects by my custom comparison functions. That works just fine, until I find out that I actually need two sets of comparison functions, which will be used in different ways at different times in my code.

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

I can't define two sets of __eq__, etc. methods in my class, and Python's built-in set type does not accept a comparator argument. I suppose I could go write a wrapper class around set, but that seems like a lot more work than necessary.

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

Is there any easier solution to this than writing my own set class?

推荐答案

假设您有此类:

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).因此,创建一个包装器:

Now, you want to put these in a set, but keyed by notkey instead of key. You can't do that as-is, because a set expects its elements to have a consistent meaning for equality—and also a consistent meaning for hash such that a == b always implies hash(a) == hash(b). So, create a wrapper:

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)

您可以将那些放在一个集合中:

And you can put those in a set:

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


例如,假设您要统一事物,为每个notkey值精确地(任意)保持一个事物.只需包裹它们,将包裹器粘在一个集合中,然后将它们解开并将未包裹的东西粘在列表中:


For example, let's say you want to uniquify your thingies, keeping exactly one thingy (arbitrarily) for each notkey value. Just wrap them, stick the the wrappers in a set, then unwrap them and stick the unwrappees in a list:

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

这是更通用的Python模式"DSU"的一部分.这代表"decorate-sort-undecorate",这在当今已经很不准确了,因为在现代Python中几乎不需要它来执行与排序相关的任务……但是从历史上看,它是有道理的.随意将其称为装饰过程无法装饰",希望它会流行起来,但不要太过努力.

This is part of a more general Python pattern called "DSU". This stands for "decorate-sort-undecorate", which is wildly inaccurate nowadays, since you almost never need it for sorting-related tasks in modern Python… but historically it made sense. Feel free to call it "decorate-process-undecorate" in hopes that it will catch on, but don't hope too hard.

现在不需要DSU进行排序的原因是,大多数排序函数都将key函数用作参数.实际上,即使是唯一化,在 itertools食谱中的unique_everseen函数取key.

The reason you don't need DSU for sorting nowadays is that most sorting functions all take key functions as arguments. In fact, even for uniquifying, the unique_everseen function in the itertools recipes takes a key.

但是,如果您仔细看一下它的功能,基本上就是DSU:

But if you look at what it does under the covers, it's basically DSU:

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

(事实上,它是一个生成器,而不是一个列表构建函数,意味着它可以即时取消装饰",这使事情变得简单一些.但除此之外,还是一样的想法.)

(The fact that it's a generator rather than a list-building function means it can "undecorate on the fly", which makes things a bit simpler. But otherwise, same idea.)

这篇关于Python中内置类型的自定义比较功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆