2011-09-26 9 views
9

Prendendo in prestito la documentazione dal __contains__ documentazionecomportamento imprevisto per il set di pitone .__ contains__

print set.__contains__.__doc__ 
x.__contains__(y) <==> y in x. 

Questo sembra funzionare bene per gli oggetti primitivi come int, basestring, ecc Ma per oggetti definiti dall'utente che definiscono il __ne__ e i metodi __eq__, ottengo un comportamento inaspettato. Ecco un codice di esempio:

class CA(object): 
    def __init__(self,name): 
    self.name = name 

    def __eq__(self,other): 
    if self.name == other.name: 
     return True 
    return False 

    def __ne__(self,other): 
    return not self.__eq__(other) 

obj1 = CA('hello') 
obj2 = CA('hello') 

theList = [obj1,] 
theSet = set(theList) 

# Test 1: list 
print (obj2 in theList) # return True 

# Test 2: set weird 
print (obj2 in theSet) # return False unexpected 

# Test 3: iterating over the set 
found = False 
for x in theSet: 
    if x == obj2: 
    found = True 

print found # return True 

# Test 4: Typcasting the set to a list 
print (obj2 in list(theSet)) # return True 

Quindi questo è un bug o una funzionalità?

+0

questa domanda dovrebbe essere in mostra qui a stackoverflow: ** come fare domande **. chiaro fino al punto, con un piccolo esempio che illustra il problema. come altri hanno risposto qui, imposta l'uso dei valori hash oppure otterrebbe la preformance delle liste .. – bjarneh

+0

nota di stile: usa 'return self.name == other.name' invece di' if cond: return True \ n return False' – jfs

risposta

2

A sethash è elementi per consentire una rapida ricerca. È necessario sovrascrivere il metodo __hash__ in modo che un elemento può essere trovato:

class CA(object): 
    def __hash__(self): 
    return hash(self.name) 

liste non usare l'hashing, ma confrontare ogni elemento come il vostro ciclo for fa.

3

Questo perché CA non implementa __hash__

Un'implementazione sensata potrebbe essere:

def __hash__(self): 
    return hash(self.name) 
7

Per set s e dicts, è necessario definire __hash__. Qualsiasi due oggetti uguali deve avere lo stesso hash per ottenere un comportamento coerente/previsto in set se dicts.

Vorrei raccomandare utilizzando un metodo _key, e poi basta riferimento che ovunque sia necessario la parte della voce da confrontare, proprio come si chiama __eq__ da __neq__ invece di reimplementare esso:

class CA(object): 
    def __init__(self,name): 
    self.name = name 

    def _key(self): 
    return type(self), self.name 

    def __hash__(self): 
    return hash(self._key()) 

    def __eq__(self,other): 
    if self._key() == other._key(): 
     return True 
    return False 

    def __ne__(self,other): 
    return not self.__eq__(other) 
Problemi correlati