Estoy haciendo una validación de los datos de entrada de un programa que he creado. Estoy haciendo esto con afirmar. Si surge la afirmación, quiero saber en qué parte de los datos se produce, así que quiero obtener el valor que surge de la afirmación.
assert all(isinstance(e, int) for l1 in sequence.values() for l2 in l1 for e in l2),"Values of the dictionnary aren't lists of integers. Assert found in '{l2}'" # This code doesn't workNo cuando se usa all , ya que no expone la "variable de iteración". Necesitará un bucle anidado explícito. También olvidaste el prefijo f'' para denotar una cadena f:
for l1 in [['a']]: for l2 in l1: for e in l2: assert isinstance(e, int), f"Values of the dictionnary aren't lists of integers. Assert found in '{l2}'" AssertionError: Values of the dictionnary aren't lists of integers. Assert found in 'a'Puede usar una expresión de asignación para capturar el "testigo" de all los False que regresan. Para ello, eliminaremos algunos generadores. Usaremos map para aplicar isinstance a cada valor de l2 , lo que nos permite capturar el valor actual de l2 en una variable que persistirá para su uso en el mensaje de assert . También usaremos itertools.chain para eliminar la necesidad del nombre l1 .
from itertools import chain def is_int(x): return isinstance(x, int) sequence = { 'key1': [[1, 2, 3], [4, 5, 6]], 'key2': [[7, 8, 9], ['a', 11, 12]] } assert all(all(map(is_int, (witness := l2))) for l2 in chain(*sequence.values())), \ f"Values of the dictionary aren't lists of integers. Assert found in '{witness}'" Con una pequeña modificación, puede iterar sobre la sequence.items() para que también pueda capturar la clave cuya lista contiene el infractor l2 . Lo dejo como ejercicio para el lector.
Desempaquetaría todas sus e's y luego haría una afirmación:
# Assuming l1 is a list of lists l1 = [[1,2,3], [4,5,6], ["7", 8, 9]] # TO TEST SUBLISTS l2 = [x for x in l1] for sublist in l2: assert all([isinstance(e, int) for x in sublist]), f'Values isn\'ta list of integers: {sublist}' # TO TEST FOR INDIVIDUAL VALUES all_e = [y for x in l1 for y in x] # To raise an error on each value: for e in all_e: assert(isinstance(e, int)), f'Value isn\'t an int: {e}' # To operate in one line assert all([isinstance(e, int) for x in all_e]), f'Values aren\'ta list of integers: {all_e}'Podría recordarlo en una variable que se filtra simplemente insertando if [witness := l2] :
sequence = { # thanks chepner 'key1': [[1, 2, 3], [4, 5, 6]], 'key2': [[7, 8, 9], ['a', 11, 12]] } assert all(isinstance(e, int) for l1 in sequence.values() for l2 in l1 if [witness := l2] for e in l2), f"Values of the dictionnary aren't lists of integers. Assert found in '{witness}'"Producción:
Traceback (most recent call last): File ".code.tio", line 6, in <module> assert all(isinstance(e, int) AssertionError: Values of the dictionnary aren't lists of integers. Assert found in '['a', 11, 12]' También podría usar (witness := l2) aquí en lugar de [witness := l2] , pero este último es aplicable en general.