2011-08-22 17 views
45

Quali metodi devono essere sovrascritti/implementati quando si rendono le classi definite dall'utente ordinabili e/o lavabili in python?Definizione di una classe definita dall'utente pitone, ordinabile, lavabile

Quali sono i trucchi a cui prestare attenzione?

Digito dir({}) nel mio interprete per ottenere un elenco di metodi su dict incorporato. Di questi, suppongo che ho bisogno di un po 'di attuare un sottoinsieme di

['__cmp__', '__eq__', '__ge__', '__gt__', '__hash__', '__le__', '__lt__', '__ne__'] 

C'è una differenza in cui i metodi devono essere attuate per python3 al contrario di python2?

+3

Buona discussione qui: http://stackoverflow.com/q/1061283/641766. La differenza tra Python 2.xe 3.x è che '__cmp__' è stato rimosso. – zeekay

risposta

51

Ho quasi postato questo come commento alle altre risposte, ma è davvero una risposta di per sé.

Per rendere gli oggetti ordinabili, è sufficiente implementare __lt__. Questo è l'unico metodo utilizzato dall'ordinamento incorporato.

Gli altri confronti o functools.total_ordering sono necessari solo se si desidera effettivamente utilizzare gli operatori di confronto con la classe.

Per rendere gli articoli lavabili, si implementa __hash__ come altri hanno notato. Dovresti anche implementare __eq__ in modo compatibile - gli elementi equivalenti dovrebbero avere lo stesso hash.

+0

quindi una scarsa implementazione di '__lt__' potrebbe causare l'ordinamento di Python in modo imprevedibile? (ad esempio, se x .__ lt __ (y) ey .__ lt __ (x)) –

+3

non so "imprevedibilmente", sarà coerente se alimentato con lo stesso input, ma un diverso ordine di input potrebbe causare diversi articoli per essere in un ordine diverso. Sì, se implementi impropriamente il confronto usato per ordinare, Python ordinerà in modo errato. Suggerirei una funzione '__key__' che trasforma l'istanza in una tupla, quindi ha solo entrambi' __lt__' ('self .__ chiave __() agf

2

Ci sono alcuni modi per contrassegnare il tuo oggetto ordinabile. In primo luogo - confronto ricco, definito da un insieme di funzioni:

object.__lt__(self, other) 
object.__le__(self, other) 
object.__eq__(self, other) 
object.__ne__(self, other) 
object.__gt__(self, other) 
object.__ge__(self, other) 

Inoltre è possibile definire una sola funzione:

object.__cmp__(self, other) 

E l'ultima Occorre definire se si desidera definire personalizzato __hash__ funzione . Vedi lo doc.

+1

In Python 3, "[...] il metodo speciale' __cmp __() 'non è più supportato," vedere la [sezione pertinente qui] (https://docs.python.org/release/3.0.1/whatsnew /3.0.html#ordering-comparisons). –

10

non v'è alcuna differenza tra Python 2 e 3.

Per sortability:

È necessario definire metodi di confronto. Questo rende i tuoi oggetti ordinabili. In generale, non si dovrebbe preferire __cmp__().

Di solito uso decoratore functools.total_ordering.

functools.total_ordering (cls) Data una classe che definisce una o più ricchi metodi di ordinamento confronto, questa classe decoratore fornisce il resto. Ciò semplifica lo sforzo richiesto per specificare tutti i possibili operazioni ricchi di confronto:

La classe deve definire uno dei __lt__(), __le__(), __gt__() o __ge__(). Inoltre, la classe deve fornire un metodo __eq__().

È necessario prestare attenzione ai metodi di confronto per avere effetti collaterali. Non vuoi cambiare la tua classe quando fai i confronti.

Per hashing:

Si dovrebbe implementare __hash__() metodo. Penso che il modo migliore stia ritornando hash(repr(self)), quindi il tuo hash sarebbe unico.

+0

Per un esempio di 'functools.total_ordering' dalla documentazione, consultare [here] (https://docs.python.org/2/library/functools.html#functools.total_ordering). –

0

Il metodo __lt__(self,other) è la soluzione per rendere ordinabile la classe.
Può essere utilizzato non solo per il metodo integrato sorted(iterable), ma anche per la coda di priorità tramite il modulo heapq.

Inoltre, non mi piace il design di Python, quindi molti metodi '__ge__', '__gt__', '__le__', '__lt__', '__ne__' sono non intuitivi per tutto!
Come Java Interface Comparable<T> (vedere java doc) restituisce un numero intero negativo, zero o un numero intero positivo poiché questo oggetto è minore, uguale o maggiore dell'oggetto specificato, ovvero diretto e intuitivo!

Problemi correlati