any() y all() comprueban condiciones sobre iterables de forma eficiente usando short-circuit evaluation: se detienen en cuanto conocen el resultado, sin procesar el resto de los elementos.
Funcionamiento básico
# any(): True si al menos UN elemento es truthy print(any([False, False, True, False])) # True print(any([0, "", None, False])) # False print(any([])) # False (vacío) # all(): True si TODOS los elementos son truthy print(all([True, True, True])) # True print(all([True, False, True])) # False print(all([])) # True (vacío vacuously true) # Con listas de números numeros = [2, 4, 6, 8, 10] print(all(x % 2 == 0 for x in numeros)) # True todos pares print(any(x > 5 for x in numeros)) # True alguno > 5
Short-circuit evaluation
Ambas funciones se detienen en cuanto pueden determinar el resultado final, lo que las hace eficientes con generadores grandes:
def comprobar(x):
print(f" comprobando {x}")
return x > 0
datos = [1, 2, -3, 4, 5]
print("any() con negativos:")
resultado = any(comprobar(x) for x in datos)
# comprobando 1 ? True ? se detiene aquí
print(f"Resultado: {resultado}n")
datos_negativos = [-1, -2, -3]
print("all() con negativos:")
resultado = all(comprobar(x) for x in datos_negativos)
# comprobando -1 ? False ? se detiene aquí
print(f"Resultado: {resultado}")
Validación de formularios
def validar_formulario(datos):
campos_requeridos = ["nombre", "email", "edad"]
# Comprobar que todos los campos existen y tienen valor
if not all(datos.get(campo) for campo in campos_requeridos):
return False, "Faltan campos obligatorios"
# Comprobar tipos
if not isinstance(datos.get("edad"), int):
return False, "La edad debe ser un número entero"
if not 0 < datos["edad"] < 150:
return False, "Edad fuera de rango"
return True, "OK"
datos1 = {"nombre": "Ana", "email": "[email protected]", "edad": 28}
datos2 = {"nombre": "Luis", "email": "", "edad": 34} # email vacío
print(validar_formulario(datos1)) # (True, 'OK')
print(validar_formulario(datos2)) # (False, 'Faltan campos obligatorios')
Comprobación de permisos
permisos_usuario = {"leer", "escribir"}
permisos_admin = {"leer", "escribir", "ejecutar", "borrar"}
def puede_acceder(usuario_permisos, recurso_requerido):
"""True si el usuario tiene TODOS los permisos requeridos."""
return all(p in usuario_permisos for p in recurso_requerido)
def tiene_algun_permiso(usuario_permisos, permisos_posibles):
"""True si el usuario tiene AL MENOS UNO de los permisos."""
return any(p in usuario_permisos for p in permisos_posibles)
operacion_requerida = ["leer", "ejecutar"]
print(puede_acceder(permisos_usuario, operacion_requerida)) # False
print(puede_acceder(permisos_admin, operacion_requerida)) # True
print(tiene_algun_permiso(permisos_usuario, ["ejecutar", "borrar"])) # False
print(tiene_algun_permiso(permisos_admin, ["ejecutar", "borrar"])) # True
Procesado de datos
usuarios = [
{"nombre": "Ana", "verificado": True, "activo": True},
{"nombre": "Luis", "verificado": False, "activo": True},
{"nombre": "María", "verificado": True, "activo": False},
]
# ¿Todos verificados?
todos_verificados = all(u["verificado"] for u in usuarios)
print(todos_verificados) # False
# ¿Alguno inactivo?
alguno_inactivo = any(not u["activo"] for u in usuarios)
print(alguno_inactivo) # True
# Filtrar los que cumplen múltiples condiciones
validos = [u for u in usuarios if u["verificado"] and u["activo"]]
print([u["nombre"] for u in validos]) # ['Ana']
any() vs all() con generadores vs listas
# BIEN: generador short-circuit real
if any(es_primo(n) for n in rango_grande):
print("Hay al menos un primo")
# MAL: lista evalúa TODO antes de any()
if any([es_primo(n) for n in rango_grande]):
print("Hay al menos un primo")
Usa siempre una expresión generadora (sin corchetes) cuando pases a any() o all(). De esta forma el short-circuit funciona de verdad y no evalúas el iterable completo antes de comprobar la condición.
