比方说,你有这个类:
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)
例如,假设你想uniquify你一样的东西,保持正好一个啄(任意)为每个notkey
值。只是包装他们,粘在包装中的一组,然后解开他们和粘unwrappees在一个列表:
wts = set(WrappedThingy(thingy) for thingy in thingies)
thingies = [wt.thingy for wt in wts]
这就是所谓的“DSU”更一般的蟒纹的一部分。这意味着“装饰 - 排序 - 未装饰”,这在当今是非常不准确的,因为在现代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
(这是一个发电机,而不是一个列表的建筑功能,这意味着它可以“飞去除装饰” ,这使得事情变得简单一些,但其他方面也是如此)
您不能以仅等于某些时间的集合存储对象。就集合而言,它们要么是平等的,要么是不平等的。 – 2013-04-30 18:46:09
通常的解决方法是“装饰”列表中的元素:根据备用比较元素存储相同的包装元素。这在评论中有点难以解释,但如果听起来很有希望,我可以写出一个答案。 – abarnert 2013-04-30 18:48:55
您可以在自己的类中编写一个包装器,而不是围绕集编写包装器,该包装器提供了替代等式定义。然后当你需要这个其他的等式定义时,有一组原始类的对象和另一组这些“替代”对象。 – BrenBarn 2013-04-30 18:49:20