2010-09-09 13 views
5

Si entiendo correctamente, se llama a la función __cmp __() de un objeto para evaluar todos los objetos en una colección mientras determina si un objeto es miembro o 'en' la colección. Sin embargo, esto no parece ser el caso para los conjuntos:Entender membresía de objeto python para conjuntos

class MyObject(object): 
    def __init__(self, data): 
     self.data = data 

    def __cmp__(self, other): 
     return self.data-other.data 

a = MyObject(5) 
b = MyObject(5) 

print a in [b]   //evaluates to True, as I'd expect 
print a in set([b])  //evaluates to False 

Cómo se analiza una membresía objeto en un conjunto, entonces?

Respuesta

2
>>> xs = [] 
>>> set([xs]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'list' 

Lo tienes. Establece hashes de uso, muy similares a los dicts. Esto ayuda mucho al rendimiento (las pruebas de membresía son O (1) y muchas otras operaciones dependen de las pruebas de membresía), y también se ajusta bien a la semántica de los conjuntos: los elementos de conjunto deben ser únicos y diferentes elementos producirán hashes diferentes, mientras que los mismos hash indicar (bueno, en teoría) duplicados.

Desde el defecto __hash__ es sólo id (que es bastante estúpida en mi humilde opinión), dos instancias de una clase que hereda object 's __hash__ nunca hash al mismo valor (bueno, a no ser que el espacio de direcciones es más grande que el sizeof el hash)

0

Un conjunto utiliza un dict detrás de las escenas, por lo que la declaración "in" está comprobando si el objeto existe como una clave en el dict. Como su objeto no implementa una función hash, la función hash predeterminada para objetos usa la identificación del objeto. Entonces, aunque a y b son equivalentes, no son el mismo objeto, y eso es lo que se está probando.

5

Adición de un método __hash__ a su clase produce esto:

class MyObject(object): 
    def __init__(self, data): 
     self.data = data 

    def __cmp__(self, other): 
     return self.data - other.data 

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


a = MyObject(5) 
b = MyObject(5) 

print a in [b] # True 
print a in set([b]) # Also True! 
+0

Eso es exactamente lo que estaba buscando. Gracias :) – jifa

+0

Aunque eso debería leer 'return hash (self.data)'. – delnan

+0

// También: para detectar mis hábitos de comentarios que no son de pitón. – jifa

1

Como otros señalaron, los objetos no tienen una __hash__ para que utilice el ID por defecto como un hash, y se puede modificarlo así Nathon sugerido, PERO lea the docs about __hash__, específicamente los puntos sobre cuándo debe y no debe hacer eso.

+0

léelos después de la respuesta anterior - cosas buenas :) – jifa

Cuestiones relacionadas