2016-11-25 4 views
2

J'ai défini une classe que j'essaie de rendre malléable. En outre, il existe une énumération qui utilise les objets de cette classe en tant que valeurs de ses membres enum.Interaction d'une classe hashable avec Enum en Python

from enum import Enum 


class Dummy(object): 
    def __init__(self, name, property_): 
     self.name = name    # can only be a string 
     self.property = property_ # can only be a string 

    def __hash__(self): 
     # print "Hash called for ", self 
     # print("----") 
     return hash(self.property) 

    def __eq__(self, other): 
     # print "Eq called for: " 
     # print self 
     # print other 
     return (self.property == other.property) 

    def __ne__ (self, other): 
     return not (self == other) 

    def __str__(self): 
     return (self.name + "$" + self.property) 


class Property(Enum): 
    cool = Dummy("foo", "cool") 
    hot = Dummy("bar", "hot") 

Bien que cela fonctionne bien, je pris conscience - en décochant commentant les déclarations print - que les __hash__ et __eq__ méthodes magiques sont invoquées pour les deux valeurs membres ENUM. Pourquoi cela est-il ainsi? Ne sont-ils pas utilisés seulement pendant les contrôles de hachage et d'égalité?

En outre, si je change la classe enum à la suivante, tout l'enfer se déchaîne.

class Property(Enum): 
    cool = Dummy("foo", "cool") 
    hot = [Dummy("bar-1", "hot-1"), Dummy("bar-2", "hot-2")] 

La méthode magique __eq__ semble être appelé à l'objet Dummy correspondant à Property.cool et la liste correspondant à Property.hot, comme en témoigne la sortie:

Hash called for foo$cool 
---- 
Eq called for: 
foo$cool 
[<__main__.Dummy object at 0x7fd36633f2d0>, <__main__.Dummy object at 0x7fd36633f310>] 
---- 
Traceback (most recent call last): 
    File "test.py", line 28, in <module> 
    class Property(Enum): 
    File "/blah/.local/lib/python2.7/site-packages/enum/__init__.py", line 237, in __new__ 
    if canonical_member.value == enum_member._value_: 
    File "test.py", line 19, in __eq__ 
    return (self.property is other.property) 
AttributeError: 'list' object has no attribute 'property' 

Pourquoi est-ce qui se passe? Pourquoi les méthodes magiques sont-elles appelées en premier lieu, et pourquoi __eq__ est-il appelé sur un objet de classe et une liste?

Veuillez noter que ceci est seulement un exemple représentatif, et le cas réel d'utilisation fait que cette conception - enum avec des valeurs comme des listes d'objets de classe traitables - semble moins bizarre.

Répondre

2

La classe Enum compare ses valeurs d'objet membre pour voir s'il existe des alias d'un autre. Par exemple, dans le Enum suivant, à la fois a et b représentent la même valeur, alors que a devrait apparaître dans la liste des membres (alias ne le font pas):

class A(Enum): 
    a=1 
    b=1 

Vous pouvez le vérifier en regardant la source code pour la ligne qui a effectué le contrôle d'égalité: source

Pour le hachage, ceci est effectué pour fournir une recherche par valeur des membres enum. Encore une fois, cela peut être trouvé dans le source code

+0

Cela répond à tout; Merci. Ainsi, les valeurs des membres enum ne peuvent pas être un objet mutable, comme une liste, qui n'est pas tabouable. – Shobhit

+1

Ils peuvent être. Si la valeur n'est pas modifiable, elle ne sera pas incluse dans la table de recherche par valeur, donc essayer de la trouver par valeur fera une boucle sur les membres et vérifiera l'égalité à la place. – 3Doubloons