2011-09-26 11 views
9

El préstamo de la documentación de la documentación __contains__comportamiento inesperado para un conjunto de pitón .__ contains__

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

Esto parece funcionar bien para los objetos primitivos como int, cadena base, etc, pero para los objetos definidos por el usuario que definen el __ne__ y __eq__ métodos, obtengo un comportamiento inesperado. Aquí hay un código de muestra:

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 

¿Es esto un error o una característica?

+0

esta pregunta debe ser en exhibición aquí en stackoverflow: ** cómo hacer preguntas **. claro al punto, con un pequeño ejemplo que ilustra el problema. como otros han respondido aquí, los conjuntos usan valores hash o de lo contrario obtendrían el rendimiento de las listas. – bjarneh

+0

nota de estilo: use 'return self.name == other.name' en lugar de' if cond: return True \ n return False' – jfs

Respuesta

2

A set hashes de TI de elementos para permitir una búsqueda rápida. Usted tiene que sobreescribir el método __hash__ forma que un elemento se puede encontrar:

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

listas no utilizar hash, pero comparar cada elemento como su bucle for hace.

3

Esto se debe a CA no implementa __hash__

Una aplicación sensata sería:

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

Para set s y dicts, es necesario definir __hash__. Cualquiera de los dos objetos que sean iguales debe hacer lo mismo para obtener un comportamiento consistente/esperado en set sy dicts.

Yo recomendaría el uso de un método _key, y luego simplemente hacer referencia a que cualquier lugar que necesita la parte del elemento de comparar, tal como se llama a __eq__ de __neq__ en lugar de reimplementar que:

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) 
Cuestiones relacionadas