2011-11-03 3 views
1

Je suis sûr qu'il y a un terme pour ce que je cherche, ou s'il n'y en a pas, il y a une très bonne raison pour laquelle j'essaie de faire est en fait idiot.Obtenir une instance de classe où une certaine propriété a une certaine valeur

Mais de toute façon. Je me demande s'il existe un moyen (quasi) intégré de trouver une certaine instance de classe qui a une propriété définie sur une certaine valeur.

Un exemple:

class Klass(object): 
    def __init__(self, value): 
     self.value = value 
    def square_value(self): 
     return self.value * self.value 

>>> a = Klass(1) 
>>> b = Klass(2) 
>>> instance = find_instance([a, b], value=1) 
>>> instance.square_value() 
1 
>>> instance = find_instance([a, b], value=2) 
>>> instance.square_value() 
4 

Je sais que je pourrais écrire une fonction qui effectue une boucle dans tous les cas Klass et renvoie ceux avec les valeurs demandées. D'un autre côté, cette fonctionnalité semble déjà exister dans Python, et si ce n'est pas le cas, il doit y avoir de très bonnes raisons pour lesquelles ce n'est pas le cas. En d'autres termes, ce que j'essaie de faire ici peut être fait d'une manière bien meilleure.

(Et bien sûr, je ne cherche pas un moyen de mettre une valeur en carré.Ce qui précède est juste un exemple de la construction que j'essaie de rechercher).

+0

Ceci est très vague. Pourriez-vous expliquer ce que vous essayez d'accomplir? Peut-être ajouter du code? – Thomas

+0

qui a quoi ... – rossipedia

+0

Désolé - J'ai poussé dans le champ des tags et soumis la question trop tôt. – LaundroMat

Répondre

4

Utiliser un filtre:

filter(lambda obj: obj.value == 1, [a, b]) 

Filtre renvoie une liste d'objets qui répondent à l'exigence que vous spécifiez. Docs: http://docs.python.org/library/functions.html#filter

Basiquement, filter(fn, list) effectue une itération sur list et applique fn à chaque élément. Il recueille tous les éléments pour lesquels fn renvoie true, les place ensuite dans une liste et les renvoie. NB: le filtre renverra toujours une liste, même s'il n'y a qu'un seul objet qui correspond. Donc, si vous ne vouliez retourner la première instance qui correspond, il vous faudrait quelque chose comme:

def find_instance(fn, objs): 
    all_matches = filter(fn, objs) 
    if len(all_matches) == 0: 
     return False # no matches 
    else: 
     return all_matches[0] 

ou, mieux encore,

def find_instance(fn, objs): 
    all_matches = filter(fn, objs) 
    return len(all_matches) > 0 and all_matches[0] # uses the fact that 'and' returns its second argument if its first argument evaluates to True. 

Ensuite, vous appelez cette fonction comme ceci:

instance = find_instance(lambda x: x.value == 1, [a, b]) 

puis instance serait a.

2

Une version plus efficace de la réponse de Ord, si vous êtes à la recherche d'une seule instance de correspondance, serait

def find_instance(fn, objs): 
    all_matches = (o for o in objs if fn(objs)) 
    return next(all_matches, None) 

instance = find_instance(lambda x: x.value == 1, [a, b]) 

Cela arrêtera la recherche dès que vous trouverez le premier match (bon si votre fonction de test est cher ou votre liste est grande), ou None s'il n'y a pas de correspondances.

Notez que la fonction next est nouvelle dans Python 2.6; dans une version plus ancienne, je pense que vous avez à faire

try: 
    return all_matches.next() 
except StopIteration: 
    return None 

Bien sûr, si vous faites juste une fois, vous pouvez le faire comme un paquebot:

instance = next((o for o in [a, b] if o.value == 1), None) 

Ce dernier a l'avantage de ne pas faire un tas d'appels de fonction et pourrait donc être légèrement plus rapide, bien que la différence sera probablement triviale.

+2

Le code de Dougal est un exemple d'expression de générateur (notez comment il a joint le bit 'o for o in ...' avec() au lieu de []. Cela ne pré-compile pas la liste des correspondances, il crée simplement des instructions Lorsque vous dites 'next (correspond, None)', Python commence à exécuter les instructions, mais il s'arrête quand il génère la première correspondance (vous pouvez obtenir plus de correspondances en appelant plusieurs fois next()) Le bit 'None' indique en principe au générateur de retourner None s'il n'y a pas de correspondance: Docs pour les expressions de générateur: http://docs.python.org/tutorial/classes.html#generator-expressions – Ord

Questions connexes