2009-06-09 7 views
4

J'utilise la compréhension de la liste suivante:valeurs Mise en cache dans la liste Python compréhensions

resources = [obj.get("file") for obj in iterator if obj.get("file") != None] 

est-il un moyen de « cache » la valeur de obj.get("file") quand il est vérifié dans l'instruction if afin qu'il ne appeler à nouveau get sur obj quand il génère la liste de retour?

Répondre

6

Si vous voulez rester avec la liste/iterator compréhensions au lieu d'utiliser filter vous pouvez simplement utiliser:

resources = [file_obj 
      for file_obj in (obj.get("file") for obj in iterator) 
      if file_obj is not None] 
+0

Merci, c'est la solution générale que je cherchais. – Kai

9
resources = filter(None, (obj.get("file") for obj in iterator)) 

Voir la documentation filter pour savoir comment fournir votre propre fonction d'évaluation. Le passage None pour la fonction (comme ci-dessus) filtre toutes les valeurs qui ne sont pas vraies.

Si obj.get() renvoie un objet qui a une méthode bizarre __nonzero__ alors vous devez passer lambda obj: obj != None pour obtenir exactement le même résultat que votre code d'origine.

+0

« un objet qui a une __nonzero__ bizarre » - comme un int, ou une str. –

1

Essayez quelque chose comme ceci:

resources = filter(lambda x: x is not None, [obj.get("file") for ob jin iterator]) 
+0

Vous n'avez pas besoin de la fonction lambda dans votre filtre. En passant None, la valeur par défaut est la fonction identity (donc tout objet évalué à false sera filtré). http://docs.python.org/library/functions.html#filter – tgray

+0

A la deuxième réflexion, vous pourriez vouloir le lambda si vous avez d'autres éléments "Faux" dans votre itérable (c'est-à-dire 0). – tgray

+0

Hmm. même si je n'en ai pas besoin, j'aime l'explicite du lambda. – SingleNegationElimination

1

Créer un dict temporaire pour contenir des valeurs. Ensuite, créez une fonction qui utilise dict comme un cache, et utiliser cette fonction dans la compréhension de la liste, comme suit:

obj_cache = {} 

def cache_get (target, key): 
    if (target, key) not in obj_cache: obj_cache[(target, key)] = target.get(key) 
    return obj_cache[(target, key)] 

resources = [cache_get(obj, "file") for obj in iterator if cache_get(obj, "file") != None] 

En outre, vous savez probablement déjà (et si oui, s'il vous plaît ne pas tenir compte de cette réponse), mais à moins que obj.get ("file") ne fasse un appel de base de données, ouvre un fichier, effectue une requête sur un réseau, ou fasse quelque chose d'autre potentiellement coûteux, l'appeler deux fois par itération est probablement inoffensif. seulement en ajoutant O (n) à votre coût.

Questions connexes