2010-07-24 3 views
3

Supposons que je l'objet suivant:liste Python, le nom de l'objet de recherche, conseils d'efficacité

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

    def __repr__(self): 
    return self.name 

Et une liste contenant plusieurs instances, telles que:

list = [Foo(name='alice'), Foo(name='bob'), Foo(name='charlie')] 

Si je veux trouver un objet avec un nom donné, je pouvais utiliser ce qui suit:

def get_by_name(name, list): 
    return [foo for foo in list if foo.name == name][-1] 

ce qui serait évidemment dire:

print get_by_name('alice', list) 
>> alice 

Cependant, existe-t-il une structure de données ou un procédé plus efficace pour extraire de tels objets? En réalité, les noms d'objets ne sont connus qu'à l'exécution et pourraient en théorie changer tout au long du cycle de vie de l'objet.

Un conseil?

MISE À JOUR:

Merci à Matt menuisiers réponse, j'ont mis à jour pour soutenir plusieurs de Foo avec le même nom:

class Foo(object): 
    _all_names = {}  
    def __init__(self, name=None): 
     self._name = None 
     self.name = name   
    @property 
    def name(self): 
     return self._name   
    @name.setter 
    def name(self, name): 
     if self._name is not None: 
      self._all_names[self._name].remove(self) 
     self._name = name 
     if name is not None: 
      self._all_names.setdefault(name, []).append(self) 
    @classmethod 
    def get_by_name(cls, name): 
     return cls._all_names[name]   
    def __repr__(self): 
     return "{0}".format(self.name) 

l = [Foo("alice"), Foo("bob"), Foo('alice'), Foo('charlie')] 
print Foo.get_by_name("alice") 
print Foo.get_by_name("charlie") 

Les commentaires sur cette approche?

+0

Un objet avec un prénom ou un * Foo *? –

+0

Voir ma mise à jour à la question. – epoch

+0

Voir ce que vous en pensez maintenant. –

Répondre

8

Essayez ceci pour la taille:

class Foo(object): 
    _all_names = {} 
    def __init__(self, name=None): 
     self.name = name 
    @property 
    def name(self): 
     return self._name 
    @name.setter 
    def name(self, name): 
     self._name = name 
     self._all_names[name] = self 
    @classmethod 
    def get_by_name(cls, name): 
     return cls._all_names[name] 
    def __str__(self): 
     return "Foo({0})".format(self.name) 

a = Foo("alice") 
b = Foo("bob") 
print Foo.get_by_name("alice") 

Gardez à l'esprit, il a gardé un minimum de transmettre l'idée, il y a beaucoup de réglages et contrôles que vous pouvez faire ici et là.

+0

Bonne idée. Vous devriez ajouter 'del self._all_names [self._name]' au setter –

+0

@ THC4k: Je l'ai considéré, mais il faudrait 'hasattr', et les contrôles clés pour éviter les exceptions, l'exemple est suffisant pour commencer. –

+0

Quel serait le meilleur moyen de mettre à jour _all_names lorsqu'une instance de Foo est supprimée? – epoch

1

La situation est un peu confuse.

Vous allez rechercher cet objet dans une liste qui est une structure de données linéaire. La seule façon de chercher quelque chose est de le parcourir un par un. Cela fait croître le temps linéairement avec la longueur de la liste. Donc, est où votre problème de vitesse est.

La façon d'obtenir des gains de vitesse est d'utiliser une sorte de schéma de hachage pour garder vos objets directement indexables par la clé qui vous intéresse (dans votre cas, name). Cela vous permettra de rechercher un objet d'une manière similaire à la recherche par clé de dictionnaire. C'est une opération à temps constant. C'est essentiellement ce que fait la réponse de Matt. Il garde un «index» en tant que structure de niveau classe afin que vous puissiez rechercher des choses en utilisant le hachage plutôt qu'en faisant une liste.

Questions connexes