2010-07-11 2 views
13

dire che ho un namedtuple come questo:Creazione di un namedtuple con una funzione di hash personalizzato

FooTuple = namedtuple("FooTuple", "item1, item2") 

e voglio la seguente funzione da utilizzare per l'hashing:

foo_hash(self): 
    return hash(self.item1) * (self.item2) 

voglio questo perché ho voglio che l'ordine di item1 e di item2 sia irrilevante (farò lo stesso per l'operatore di confronto). Ho pensato a due modi per farlo. Il primo sarebbe:

FooTuple.__hash__ = foo_hash 

Questo funziona, ma si sente violato. Così ho provato subclassing FooTuple:

class EnhancedFooTuple(FooTuple): 
    def __init__(self, item1, item2): 
     FooTuple.__init__(self, item1, item2) 

    # custom hash function here 

Ma allora ottengo questo:

DeprecationWarning: object.__init__() takes no parameters 

Allora, cosa posso fare? O è una pessima idea e dovrei scrivere la mia classe da zero?

risposta

18

Penso che ci sia qualcosa di sbagliato nel codice (suppongo che tu abbia creato un'istanza della tupla con lo stesso nome, quindi fooTuple è ora una tupla, non una classe di tuple), perché sottoclasse la tupla chiamata come quella dovrebbe funzionare. Ad ogni modo, non è necessario ridefinire il costruttore. È sufficiente aggiungere la funzione hash:

In [1]: from collections import namedtuple 

In [2]: Foo = namedtuple('Foo', ['item1', 'item2'], verbose=False) 

In [3]: class ExtendedFoo(Foo): 
    ...:  def __hash__(self): 
    ...:   return hash(self.item1) * hash(self.item2) 
    ...: 

In [4]: foo = ExtendedFoo(1, 2) 

In [5]: hash(foo) 
Out[5]: 2 
+0

Grazie, lasciando il costruttore nella sottoclasse ha risolto il problema. –

+11

Nota che 'repr (foo)' continuerà a parlare di 'Foo'. Questo potrebbe essere fatto meglio come 'class Foo (namedtuple ('Foo', ['item1', 'item2'], verbose = False)):' –

+0

presta attenzione alla risposta @ Sven [qui] (http: // stackoverflow. com/domande/4901815/oggetto-del-custom-type-as-dizionario-chiave) –