¿Existe un problema de rendimiento o mantenimiento de código con el uso
assert
como parte del código estándar en lugar de usarlo solo para fines de depuración?Es
assert x >= 0, 'x is less than zero'
mejor o peor que
if x < 0: raise Exception, 'x is less than zero'
Además, ¿hay alguna forma de establecer una regla de negocio como
if x < 0 raise error
esa? Siempre se verifica sintry/except/finally
eso, si en algún momento a lo largo del códigox
es menor que 0, se genera un error, como si se configuraassert x < 0
al inicio de una función, en cualquier lugar dentro de la función donde sex
convierte en menos de 0 se genera una excepción?
483
assert
.Respuestas:
Para poder lanzar automáticamente un error cuando x sea menor que cero en toda la función. Puedes usar descriptores de clase . Aquí hay un ejemplo:
fuente
Las afirmaciones deben usarse para probar condiciones que nunca deberían suceder . El propósito es colapsar temprano en el caso de un estado corrupto del programa.
Deben usarse excepciones para los errores que pueden ocurrir, y casi siempre debe crear sus propias clases de Excepción .
Por ejemplo, si está escribiendo una función para leer desde un archivo de configuración a un
dict
formato incorrecto en el archivo debería aparecer unConfigurationSyntaxError
, mientras que puedeassert
que no esté a punto de regresarNone
.En su ejemplo, si
x
se establece un valor a través de una interfaz de usuario o de una fuente externa, lo mejor es una excepción.Si
x
solo lo establece su propio código en el mismo programa, vaya con una aserción.fuente
assert
contiene un implícitoif __debug__
y puede optimizarse , como dice la respuesta de John MeeLas declaraciones de "afirmar" se eliminan cuando se optimiza la compilación . Entonces, sí, hay diferencias funcionales y de rendimiento.
Si utiliza
assert
para implementar la funcionalidad de la aplicación, luego optimice la implementación para la producción, estará plagado de defectos "but-it-works-in-dev".Ver PYTHONOPTIMIZE y -O -OO
fuente
raise
suException
lugar. ¡Oh, acabo de descubrir un nombre apropiadoSuspiciousOperation
Exception
con subclasesDjango
! ¡Perfecto!bandit
su código, le advertirá de esto.Los cuatro propósitos de
assert
Suponga que trabaja en 200,000 líneas de código con cuatro colegas Alice, Bernd, Carl y Daphne. Ellos llaman a tu código, tú llamas a su código.
Luego
assert
tiene cuatro roles :Informe a Alice, Bernd, Carl y Daphne qué espera su código.
Suponga que tiene un método que procesa una lista de tuplas y la lógica del programa puede romperse si esas tuplas no son inmutables:
Esto es más confiable que la información equivalente en la documentación y es mucho más fácil de mantener.
Informe a la computadora lo que su código espera.
assert
impone el comportamiento adecuado de las personas que llaman de su código. Si su código llama al código de Alices y Bernd llama al suyo, entonces sin elassert
, si el programa falla en el código de Alices, Bernd podría asumir que fue culpa de Alice, Alice investiga y podría asumir que fue su culpa, usted investiga y le dice a Bernd que en realidad fue su. Mucho trabajo perdido.Con afirma, quien recibe una llamada incorrecta, rápidamente podrán ver que fue su culpa, no la suya. Alice, Bernd y todos ustedes se benefician. Ahorra inmensas cantidades de tiempo.
Informe a los lectores de su código (incluido usted mismo) qué ha logrado su código en algún momento.
Suponga que tiene una lista de entradas y que cada una de ellas puede estar limpia (lo cual es bueno) o puede ser borrosa, trale, gullup o centelleante (que no son aceptables). Si es borroso, debe ser desenfadado; si es trale, debe ser baludo; si es gullup, debe ser troteado (y luego posiblemente también estimulado); si está centelleado, debe volver a brillar excepto los jueves. Ya tienes la idea: es algo complicado. Pero el resultado final es (o debería ser) que todas las entradas están limpias. Lo correcto es hacer un resumen del efecto de su ciclo de limpieza como
Estas declaraciones ahorran un dolor de cabeza para todos los que intentan entender exactamente qué es lo que está logrando el maravilloso ciclo. Y la más frecuente de estas personas probablemente sea usted mismo.
Informe a la computadora lo que su código ha logrado en algún momento.
Si alguna vez se olvida de marcar una entrada que la necesita después del trote,
assert
le ahorrará el día y evitará que su código rompa el de Daphne mucho más tarde.En mi opinión,
assert
los dos propósitos de documentación (1 y 3) y salvaguarda (2 y 4) son igualmente valiosos.Informar a las personas puede ser incluso más valioso que informar a la computadora porque puede evitar los mismos errores que los
assert
objetivos deben atrapar (en el caso 1) y muchos errores posteriores en cualquier caso.fuente
Además de las otras respuestas, las afirmaciones arrojan excepciones, pero solo AssertionErrors. Desde un punto de vista utilitario, las afirmaciones no son adecuadas para cuando necesita un control de grano fino sobre las excepciones que captura.
fuente
AssertionErrors
, cuando esté de acuerdo con que sea de grano grueso. En realidad, no deberías atraparlos.Lo único que está realmente mal con este enfoque es que es difícil hacer una excepción muy descriptiva usando declaraciones de afirmación. Si está buscando la sintaxis más simple, recuerde que también puede hacer algo como esto:
Otro problema es que el uso de la aserción para la verificación de condición normal es que hace que sea difícil deshabilitar las afirmaciones de depuración utilizando el indicador -O.
fuente
La palabra del idioma inglés afirmar aquí se usa en el sentido de jurar , afirmar , declarar . No significa "verificar" o "debería ser" . Significa que usted como codificador está haciendo una declaración jurada aquí:
Si el código es correcto, salvo las perturbaciones de evento único , fallas de hardware y demás, ninguna afirmación fallará . Es por eso que el comportamiento del programa para un usuario final no debe verse afectado. Especialmente, una afirmación no puede fallar incluso bajo condiciones programáticas excepcionales . Simplemente nunca sucede. Si sucede, el programador debería ser eliminado por ello.
fuente
Como se ha dicho anteriormente, las afirmaciones deben usarse cuando su código NO DEBE llegar a un punto, lo que significa que hay un error allí. Probablemente la razón más útil que puedo ver para usar una aserción es una condición invariante / pre / post. Estos son algo que debe ser cierto al principio o al final de cada iteración de un bucle o una función.
Por ejemplo, una función recursiva (2 funciones separadas, por lo que 1 maneja la entrada incorrecta y la otra maneja el código incorrecto, porque es difícil de distinguir con recursividad). Esto haría obvio si se me olvida escribir la declaración if, lo que salió mal.
Estos invariantes de bucle a menudo se pueden representar con una afirmación.
fuente
#precondition: n >= 0
una afirmación, puede escribir@precondition(lambda n: n >= 0)
__doc__
atributo dando una cadena adicional¿ Hay algún problema de rendimiento?
Recuerde "hacer que funcione primero antes de hacerlo rápido" .
Muy poco porcentaje de cualquier programa suele ser relevante por su velocidad. Siempre puede expulsar o simplificar y
assert
si alguna vez resulta ser un problema de rendimiento, y la mayoría de ellos nunca lo hará.Sea pragmático :
suponga que tiene un método que procesa una lista no vacía de tuplas y la lógica del programa se romperá si esas tuplas no son inmutables. Deberías escribir:
Esto probablemente esté bien si sus listas tienden a tener diez entradas, pero puede convertirse en un problema si tienen un millón de entradas. Pero en lugar de descartar este valioso cheque por completo, simplemente podría degradarlo a
que es barato pero que probablemente atrapará la mayor parte del todos modos errores reales del programa.
fuente
assert(len(listOfTuples)==0 or type(listOfTyples[0])==tuple)
.Bueno, esta es una pregunta abierta, y tengo dos aspectos que quiero tocar: cuándo agregar aserciones y cómo escribir los mensajes de error.
Propósito
Para explicárselo a un principiante, las aserciones son declaraciones que pueden generar errores, pero no las detectará. Y normalmente no se deben criar, pero en la vida real a veces se crían de todos modos. Y esta es una situación grave, de la cual el código no puede recuperarse, lo que llamamos un "error fatal".
A continuación, es para 'propósitos de depuración', lo que, aunque es correcto, suena muy desdeñoso. Me gusta más la formulación de 'declarar invariantes, que nunca deberían violarse', aunque funciona de manera diferente en diferentes principiantes ... Algunos 'simplemente lo entienden', y otros no encuentran ningún uso para él o reemplazan las excepciones normales, o incluso controlar el flujo con él.
Estilo
¡En Python,
assert
es una declaración, no una función! (recuerdaassert(False, 'is true')
que no subirá. Pero, teniendo eso fuera del camino:¿Cuándo y cómo escribir el 'mensaje de error' opcional?
Esto se aplica realmente a los marcos de prueba de unidad, que a menudo tienen muchos métodos dedicados para hacer afirmaciones (
assertTrue(condition)
,assertFalse(condition), assertEqual(actual, expected)
etc.). A menudo también proporcionan una forma de comentar sobre la afirmación.En el código desechable, podría prescindir de los mensajes de error.
En algunos casos, no hay nada que agregar a la afirmación:
volcado de def (algo): afirmar isinstance (algo, Dumpable) # ...
Pero aparte de eso, un mensaje es útil para la comunicación con otros programadores (que a veces son usuarios interactivos de su código, por ejemplo, en Ipython / Jupyter, etc.).
Bríndeles información, no solo filtrar detalles de implementación internos.
en vez de:
escribir:
o tal vez incluso:
Lo sé, lo sé, este no es un caso para una aserción estática, pero quiero señalar el valor informativo del mensaje.
¿Mensaje negativo o positivo?
Esto puede ser controvertido, pero me duele leer cosas como:
Estas son dos cosas contradictorias escritas una al lado de la otra. Entonces, cada vez que tengo una influencia en la base de código, presiono para especificar lo que queremos, usando verbos adicionales como 'must' y 'should', y no decir lo que no queremos.
afirmar a == b, 'a debe ser igual a b'
Entonces, obtener
AssertionError: a must be equal to b
también es legible, y la declaración parece lógica en el código. Además, puede obtener algo sin leer el rastreo (que a veces ni siquiera puede estar disponible).fuente
Tanto el uso
assert
como el aumento de excepciones tienen que ver con la comunicación.Las afirmaciones son declaraciones sobre la exactitud del código dirigido a los desarrolladores : una afirmación en el código informa a los lectores del código sobre las condiciones que deben cumplirse para que el código sea correcto. Una afirmación que falla en tiempo de ejecución informa a los desarrolladores que hay un defecto en el código que necesita ser reparado.
Las excepciones son indicaciones sobre situaciones no típicas que pueden ocurrir en tiempo de ejecución pero que no pueden resolverse mediante el código en cuestión, que se aborda en el código de llamada que se maneja allí. La aparición de una excepción no indica que hay un error en el código.
Por lo tanto, si considera la ocurrencia de una situación específica en tiempo de ejecución como un error sobre el que desea informar a los desarrolladores ("Hola desarrollador, esta condición indica que hay un error en alguna parte, por favor corrija el código"). ir para una afirmación. Si la aserción verifica los argumentos de entrada de su código, normalmente debe agregar a la documentación que su código tiene un "comportamiento indefinido" cuando los argumentos de entrada violan esas condiciones.
Si, en cambio, la ocurrencia de esa misma situación no es una indicación de un error en sus ojos, sino una posible (quizás rara pero) situación que cree que debería ser manejada por el código del cliente, plantee una excepción. Las situaciones en las que se plantea una excepción deben formar parte de la documentación del código respectivo.
La evaluación de las afirmaciones lleva algún tiempo. Sin embargo, pueden eliminarse en tiempo de compilación. Esto tiene algunas consecuencias, sin embargo, ver más abajo.
Normalmente, las aserciones mejoran la capacidad de mantenimiento del código, ya que mejoran la legibilidad al hacer explícitos los supuestos y durante el tiempo de ejecución verificar regularmente estos supuestos. Esto también ayudará a atrapar regresiones. Sin embargo, hay un problema que debe tenerse en cuenta: las expresiones utilizadas en las afirmaciones no deberían tener efectos secundarios. Como se mencionó anteriormente, las afirmaciones se pueden eliminar en el momento de la compilación, lo que significa que también desaparecerían los posibles efectos secundarios. Esto puede, sin querer, cambiar el comportamiento del código.
fuente
Una afirmación es verificar:
1. la condición válida,
2. la declaración válida,
3. lógica verdadera;
del código fuente. En lugar de fallar en todo el proyecto, da la alarma de que algo no es apropiado en su archivo fuente.
En el ejemplo 1, dado que la variable 'str' no es nula. Por lo tanto, no se plantea ninguna afirmación o excepción.
Ejemplo 1:
En el ejemplo 2, var 'str' es nulo. Por lo tanto, estamos evitando que el usuario se adelante al programa defectuoso al afirmar comunicado.
Ejemplo 2
En el momento en que no queremos depurar y nos damos cuenta del problema de aserción en el código fuente. Deshabilitar la bandera de optimización
python -O afirmarStatement.py
no se imprimirá nada
fuente
En IDE como PTVS, PyCharm, las
assert isinstance()
declaraciones Wing se pueden usar para permitir la finalización del código para algunos objetos poco claros.fuente
typing.cast
.Para lo que vale, si se trata de un código que se basa
assert
para funcionar correctamente, agregar el siguiente código garantizará que las afirmaciones estén habilitadas:fuente