Escribí un guión simple para resolver un "acertijo lógico", el tipo de acertijo de la escuela donde se le dan varias reglas y luego debe ser capaz de encontrar la solución para problemas como "Hay cinco músicos llamados A, B , C, D y E tocando en un concierto, cada uno toca uno después del otro ... si A va antes que B, y D no es el último ... ¿cuál es el orden de quién toca cuándo? etc.¿Hay un modismo de Python para evaluar una lista de funciones/expresiones con cortocircuitos?
para evaluar las posibles soluciones, escribí cada una "regla", como una función separada que evaluar si una solución posible (representado simplemente como una lista de cadenas) es válido, por ejemplo
#Fifth slot must be B or D
def rule1(solution):
return solution[4] == 'B' or solution[4] == 'D'
#There must be at least two spots between A and B
def rule2(solution):
returns abs(solution.index('A') - solution.index('B')) >= 2
#etc...
I Estoy interesado en encontrar la forma Pythonic para probar si una posible solución pasa todas esas reglas, con la capacidad de dejar de evaluar las reglas después de que la primera haya fallado.
Al principio me escribió el más simple que sea posible:
def is_valid(solution):
return rule1(solution) and rule2(solution) and rule3(solution) and ...
pero esto parecía bastante feo. Pensé que tal vez podría hacer que este leyó un poco más elegante, con algo así como una lista por comprensión ...
def is_valid(solution)
rules = [rule1, rule2, rule3, rule4, ... ]
return all([r(solution) for f in rules])
... pero luego me di cuenta de que, desde la comprensión de lista se genera antes de la función all()
se evalúa, que esto tiene el efecto secundario de no estar en cortocircuito en absoluto: cada regla se evaluará incluso si la primera devuelve False
.
Así que mi pregunta es: ¿hay una manera más Pythonic/funcional para poder evaluar una lista de True
/False
expresiones, con cortocircuitos, sin la necesidad de escribir una larga lista de return f1(s) and f2(s) and f3(s) ...
?
Así que aquí la diferencia básica es omitir los corchetes en 'return all ([r (solution) for r in rules])', ¿no se creará una lista de todos los resultados antes de evaluar 'all()'? –
Sí. En ambos casos, el argumento para 'todo' se evalúa antes de transmitirse, pero la evaluación de una lista de comprensión crea toda la lista en la memoria mientras que la evaluación de una expresión generadora crea un objeto generador, que carga los elementos a petición. – katrielalex
Perfecto, esto tiene mucho sentido - gracias –