Python: ¿Cómo establecer una variable local en la comprensión de la lista?

Tengo un método que toma una lista y devuelve un objeto.

# input a list, returns an object def map_to_obj(lst): a_list = f(lst) return a_list[0] if a_list else None 

Quiero obtener una lista que contenga todos los elementos asignados que no sea None .

Me gusta esto:

 v_list = [v1, v2, v3, v4] [map_to_obj(v) for v in v_list if map_to_obj(v)] 

Pero no parece bueno llamar dos veces al método map_to_obj en la lista de comprensión.

¿Hay alguna forma de tener variables locales en la comprensión de la lista para que pueda tener un mejor desempeño?

¿O el comstackdor lo optimiza automáticamente?

Esto es lo que quiero:

 (sml like) [let mapped = map_to_obj(v) in for v in v_list if mapped end] 

Use la lista de comprensión anidada:

[x for x in [map_to_obj(v) for v in v_list] if x]

O mejor aún, una lista de comprensión alrededor de una expresión generadora:

[x for x in (map_to_obj(v) for v in v_list) if x]

Puede evitar el recálculo utilizando el filter incorporado de python:

 list(filter(lambda t: t is not None, map(map_to_obj, v_list))) 

Una asignación de variable es solo un enlace singular:

 [x for v in l for x in [v]] 

Esta es una respuesta más general y también más cercana a lo que propusiste. Así que para tu problema puedes escribir:

 [x for v in v_list for x in [map_to_obj(v)] if x] 

Se puede establecer una variable local dentro de una comprensión haciendo trampa un poco y usando un ‘for’ adicional que “itera” a través de una tupla de 1 elemento que contiene el valor deseado para la variable local. Aquí hay una solución al problema del OP usando este enfoque:

 [o for v in v_list for o in (map_to_obj(v),) if o] 

Aquí, o es la variable local que se establece igual a map_to_obj(v) para cada v .

En mis pruebas, esto es un poco más rápido que la expresión del generador nested de Lying Dog (y también más rápido que la doble llamada del OP a map_to_obj(v) , que, sorprendentemente, puede ser más rápido que la expresión del generador nested si la función map_to_obj no es demasiado lenta ).

Las comprensiones de listas están bien para los casos simples, pero a veces la solución más simple es un simple bucle antiguo for :

 other_list = [] for v in v_list: obj = map_to_obj(v) if obj: other_list.append(obj) 

Ahora, si realmente quiere una lista comp y no quiere construir una lista tmp, puede usar las versiones de iterador de filter y map :

 import itertools as it result = list(it.ifilter(None, it.imap(map_to_obj, v_list))) 

o más simplemente:

 import itertools as it result = filter(None, it.imap(map_to_obj, v_list))) 

Las versiones de iterador no crean una lista temporal, usan una evaluación perezosa.

He descubierto una manera de usar reduce :

 def map_and_append(lst, v): mapped = map_to_obj(v) if mapped is not None: lst.append(mapped) return lst reduce(map_and_append, v_list, []) 

¿Qué tal el rendimiento de esto?