2010-04-05 4 views
1

Y a-t-il un moyen de faire une liste de classes se comporter comme un ensemble en python? Fondamentalement, je travaille sur un morceau de logiciel qui fait une comparaison de chaîne impliquée, et j'ai une classe personnalisée pour manipuler les chaînes. Par conséquent, il existe une instance de la classe pour chaque chaîne. En conséquence, j'ai une grande liste contenant toutes ces classes. Je voudrais pouvoir y accéder comme list[key], où dans ce cas, la clé est une chaîne dont la classe est basée sur (note: la chaîne ne changera jamais une fois que la classe est instanciée, elle devrait donc être gérable).Python - Accéder à une classe à partir d'une liste à l'aide d'une clé

Il me semble que je devrais être en mesure de le faire un peu facilement, en ajoutant quelque chose comme __cmp__ à la classe, mais soit je suis obtuse (probable), ou il me manque quelque chose dans les docs.

Fondamentalement, je veux être en mesure de faire quelque chose comme ceci (exemple rapide Python):

>>class a: 
... def __init__(self, x): 
... self.var = x 
... 
>>> from test import a 
>>> cl = set([a("Hello"), a("World"), a("Pie")]) 
>>> print cl 
set([<test.a instance at 0x00C866C0>, <test.a instance at 0x00C866E8>, <test.a instance at 0x00C86710>]) 
>>> cl["World"] 
<test.a instance at 0x00C866E8> 

Merci!

Modifier Quelques Tweaks supplémentaires:

class a: 
... def __init__(self, x): 
...  self.var = x 
... def __hash__(self): 
...  return hash(self.var) 
... 
>>> v = a("Hello") 
>>> x = {} 
>>> x[v]=v 
>>> x["Hello"] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
KeyError: 'Hello' 
>>> x["Hello"] 
+0

Un SET utilise des index, pas des clés.Un dictionnaire semble être plus ce que vous voulez, mais vous utilisez un passage dans une clé d'un ("Bonjour"), et en essayant de le récupérer en utilisant une valeur différente - "Bonjour". –

+0

Vous devez également définir la méthode \ _ \ _ cmp \ _ \ _ pour la classe __a__ qui sera appelée dans le cas de collisions de valeurs de hachage. – Yaroslav

+0

Veuillez utiliser les noms UpperCase pour les classes. S'il vous plaît hériter de l'objet. Comme ceci: 'class A (object)'. Cela rendra beaucoup de choses plus faciles à lire pour nous et plus faciles à comprendre pour vous aussi. –

Répondre

2

écrire Juste une classe qui se comporte un peu comme une cartographie :

class ClassDict(object): 
    def __init__(self): 
    self.classes = {} 

    def add(self, cls): 
    self.classes[cls.__name__] = cls 

    def remove(self, cls): 
    if self.classes[cls.__name__] == cls: 
     del self.classes[cls.__name__] 
    else: 
     raise KeyError('%r' % cls) 

    def __getitem__(self, key): 
    return self.classes[key] 

    def __repr__(self): 
    return 'ClassDict(%s)' % (', '.join(self.classes),) 

class C(object): 
    pass 

class D(object): 
    pass 

cd = ClassDict() 
cd.add(C) 
cd.add(D) 

print cd 

print cd['C'] 
+0

Hmmmm. Il semble que cela devrait fonctionner, mais quand j'essaie d'évaluer 'key dans ClassDict' il échoue avec un keyerror, et une instruction print dans la fonction' __getitem__' montre qu'il passe une clé de '0'. –

+0

Doh - Besoin d'ajouter '__contains__' –

+0

Je me suis retrouvé à faire cela, car cela m'a permis de gérer certains problèmes de déduplication des données que j'avais. OTOH, j'ai maintenant rencontré des problèmes avec la limite de mémoire de 2 Go 32 bits. \*soupir\* –

1

Je me souviens "set" et "dict" utilise également __hash__

De Python 2.x doc:

clés est un dictionnaire sont presque valeurs arbitraires. Les valeurs qui ne sont pas hashable, c'est-à-dire, les valeurs contenant des listes, des dictionnaires ou d'autres types mutables (qui sont comparés par valeur plutôt que par identité d'objet) ne peuvent pas être utilisés comme clés.

1

Set et dict utiliser la valeur retournée par __hash__ d'un objet méthode pour rechercher l'objet, donc cela va faire ce que vous voulez:

>>class a: 
... def __init__(self, x): 
... self.var = x 
... 
... def __hash__(self): 
... return hash(self.var) 
+0

Lorsque la classe 'a'' __hash __ (self) 'renvoie le même hachage que la chaîne' x', vous bénéficiez de l'avantage supplémentaire de cela, que vous fassiez une recherche dict sur 'a (x)' ou 'x'. – ndim

+0

Ok, mais comment insérer la classe dans le dictionnaire? Avec '__hash__' défini, essayer d'ajouter une instance de la classe à un dictionnaire me donne soit une erreur de syntaxe, soit une entrée dans le dict avec la clé étant la classe elle-même. –

0

voulez-vous quelque chose comme ça

class A(object): 
    ALL_INSTANCES = {} 
    def __init__(self, text): 
     self.text = text 
     self.ALL_INSTANCES[self.text] = self 



a1 = A("hello") 
a2 = A("world") 

print A.ALL_INSTANCES["hello"] 

sortie:

<__main__.A object at 0x00B7EA50> 
2

Pourquoi ne pas vous venez de faire:

>>> v = MyStr("Hello") 
>>> x = {} 
>>> x[v.val]=v 
>>> x["Hello"] 
MyStr("Hello") 

Pourquoi passer par toutes les difficultés d'essayer de créer un dict roulées à la main qui utilise des clés différentes que celles que vous passez dans? (c'est-à-dire "Bonjour" au lieu de MyStr ("Bonjour")).

ex.

class MyStr(object): 
    def __init__(self, val): 
     self.val = str(val) 

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

    def __str__(self): 
     return self.val 

    def __repr__(self): 
     return 'MyStr("%s")' % self.val 


>>> v = MyStr("Hello") 
>>> x = {} 
>>> x[str(v)]=v 
>>> x["Hello"] 
MyStr("Hello") 
Questions connexes