比方說,你有這個類:
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