validar utilizar try tipos sirve recent que print por para most last excepciones error ejemplos diferentes como catch python assert

python - utilizar - traceback(most recent call last) file stdin line 1 in module



¿Cuáles son los casos de uso aceptables para la declaración `assert` de python? (8)

El Wiki de Python tiene una gran guía para usar la Afirmación de manera efectiva.

Las respuestas anteriores no necesariamente aclaran la objeción -O al ejecutar Python. La cita de la página anterior:

Si Python se inicia con la opción -O, las aserciones se eliminarán y no se evaluarán.

A menudo utilizo la declaración de aserción de python para verificar la entrada del usuario y la falla si estamos en un estado corrupto. Soy consciente de que assert se elimina cuando python con el indicador -o (optimizado). Personalmente, no ejecuto ninguna de mis aplicaciones en modo optimizado, pero siento que debería alejarme de las aserciones en caso de ser así.

Se siente mucho más limpio escribir

assert filename.endswith(''.jpg'')

que

if not filename.endswith(''.jpg''): raise RuntimeError

¿Es este un caso de uso válido para assert? Si no, ¿cuál sería un caso de uso válido para la aseveración de python?


La respuesta de S.Lott es la mejor. Pero esto fue demasiado largo para agregarlo a un comentario suyo, así que lo puse aquí. De todos modos, es lo que pienso acerca de afirmar, que es básicamente que es solo una forma abreviada de hacer #ifdef DEBUG.

De todos modos, hay dos escuelas de pensamiento acerca de la verificación de entrada. Puedes hacerlo en el objetivo, o puedes hacerlo desde la fuente.

Hacerlo en el objetivo está dentro del código:

def sqrt(x): if x<0: raise ValueError, ''sqrt requires positive numbers'' root = <do stuff> return root def some_func(x): y = float(raw_input(''Type a number:'')) try: print ''Square root is %f''%sqrt(y) except ValueError: # User did not type valid input print ''%f must be a positive number!''%y

Ahora, esto tiene muchas ventajas. Probablemente, el tipo que escribió sqrt sabe más acerca de cuáles son los valores válidos para su algoritmo. En lo anterior, no tengo idea si el valor que obtuve del usuario es válido o no. Alguien tiene que verificarlo, y tiene sentido hacerlo en el código que más sabe sobre lo que es válido: el algoritmo sqrt en sí mismo.

Sin embargo, hay una penalización de rendimiento. Imagina código como este:

def sqrt(x): if x<=0: raise ValueError, ''sqrt requires positive numbers'' root = <do stuff> return root def some_func(maxx=100000): all_sqrts = [sqrt(x) for x in range(maxx)] i = sqrt(-1.0) return(all_sqrts)

Ahora, esta función va a llamar sqrt 100k veces. Y cada vez, sqrt comprobará si el valor es> = 0. Pero ya sabemos que es válido, debido a la forma en que generamos esos números: esas comprobaciones adicionales válidas son solo un desperdicio de tiempo de ejecución. ¿No sería bueno deshacerse de ellos? Y luego hay uno, que arrojará un ValueError, entonces lo atraparemos y nos daremos cuenta de que cometimos un error. Escribo mi programa confiando en la subfunción para controlarme, así que solo me preocupo por recuperarme cuando no funciona.

La segunda línea de pensamiento es que, en lugar de las entradas de verificación de función objetivo, se agregan restricciones a la definición y se requiere que la persona que llama se asegure de que está realizando una llamada con datos válidos. La función promete que con buenos datos, devolverá lo que dice su contrato. Esto evita todas esas comprobaciones, porque la persona que llama sabe mucho más sobre los datos que envía que la función objetivo, de dónde viene y qué restricciones tiene inherentemente. El resultado final de estos son los contratos de código y estructuras similares, pero originalmente fue solo por convención, es decir, en el diseño, como el comentario a continuación:

# This function valid if x > 0 def sqrt(x): root = <do stuff> return root def long_function(maxx=100000): # This is a valid function call - every x i pass to sqrt is valid sqrtlist1 = [sqrt(x) for x in range(maxx)] # This one is a program error - calling function with incorrect arguments # But one that can''t be statically determined # It will throw an exception somewhere in the sqrt code above i = sqrt(-1.0)

Por supuesto, los errores ocurren, y el contrato puede obtener violaciones. Pero hasta ahora, el resultado es casi el mismo; en ambos casos, si llamo a sqrt (-1.0), obtendré una excepción dentro del código sqrt, puedo subir la pila de excepciones y averiguar dónde está mi error.

Sin embargo, hay muchos más casos insidiosos ... supongamos que, por ejemplo, mi código genera un índice de lista, lo almacena, luego busca el índice de la lista, extrae un valor y realiza algún procesamiento. y digamos que obtenemos un índice de la lista -1 por accidente. todos esos pasos pueden completarse sin errores, pero tenemos datos incorrectos al final de la prueba y no tenemos idea de por qué.

Entonces, ¿por qué afirmar? Sería bueno tener algo con lo que podamos acercarnos a la información de depuración más cercana al fallo mientras estamos probando y probando nuestros contratos. Esto es más o menos lo mismo que la primera forma; después de todo, está haciendo exactamente la misma comparación, pero es sintácticamente más nítida y un poco más especializada para verificar un contrato. Un beneficio adicional es que una vez que esté razonablemente seguro de que su programa funciona, y está optimizando y buscando un rendimiento más alto en comparación con la capacidad de depuración, se pueden eliminar todas estas comprobaciones ahora redundantes.


Las afirmaciones deben usarse para expresar invariantes o precondiciones .
En su ejemplo, los está usando para verificar entradas inesperadas, y esa es una clase de excepciones completamente diferente.

Dependiendo de los requisitos, puede ser perfectamente correcto generar una excepción en una entrada incorrecta y detener la aplicación; sin embargo, el código siempre debe adaptarse a la expresividad, y generar un AssertionError no es tan explícito.
Mucho mejor sería levantar su propia excepción, o un ValueError .


Personalmente, uso assert para errores inesperados, o cosas que no espera que ocurran en el uso del mundo real. Se deben usar excepciones cuando se trata de la entrada de un usuario o archivo, ya que pueden detectarse y se le puede decir al usuario "Hey, ¡esperaba un archivo .jpg !!"


Totalmente válido. La afirmación es una reclamación formal sobre el estado de su programa.

Debes usarlos para cosas que no pueden ser probadas. Sin embargo, son útiles para cosas que crees que puedes probar como una comprobación de tu lógica.

Otro ejemplo.

def fastExp( a, b ): assert isinstance(b,(int,long)), "This algorithm raises to an integer power" etc.

Aún otra. La afirmación final es un poco tonta, ya que debería ser comprobable.

# Not provable, essential. assert len(someList) > 0, "Can''t work with an empty list." x = someList[] while len(x) != 0: startingSize= len(x) ... some processing ... # Provable. May be Redundant. assert len(x) < startingSize, "Design Flaw of the worst kind."

Aún otra.

def sqrt( x ): # This may not be provable and is essential. assert x >= 0, "Can''t cope with non-positive numbers" ... # This is provable and may be redundant. assert abs( n*n - x ) < 0.00001 return n

Hay muchas razones para hacer afirmaciones formales.


assert se utiliza mejor para el código que debería estar activo durante las pruebas cuando seguramente se ejecutará sin -o

Personalmente, nunca puede ejecutar con -o pero ¿qué sucede si su código termina en un sistema más grande y el administrador quiere ejecutarlo con -o ?

Es posible que el sistema parezca funcionar bien, pero hay errores sutiles que se han activado al ejecutar con -o


Línea botton:

  • assert y su semántica son un patrimonio de idiomas anteriores.
  • El drástico cambio de enfoque de Python ha demostrado que el uso tradicional es irrelevante.
  • No se han propuesto oficialmente otros casos de uso a partir de este escrito, aunque existen ideas para reformarlo y convertirlo en un control de propósito general.
  • Se puede usar (y de hecho se usa) como un control de propósito general como lo es ahora si está de acuerdo con las limitaciones.

El caso de uso previsto con el que se crearon originalmente las declaraciones ASSERT fue:

  • para hacer verificaciones de cordura que son relevantes pero que se consideran demasiado costosas o innecesarias para el uso de producción.
    • Por ejemplo, estas pueden ser comprobaciones de entrada para funciones internas, verifica que se haya pasado a free() un puntero que previamente se obtuvo de malloc() y así, verificaciones de integridad de la estructura interna después de operaciones no triviales con ellas, etc.

Esto fue un gran problema en los viejos tiempos y todavía está en entornos diseñados para el rendimiento. Esa es toda la razón de su semántica en, por ejemplo, C ++ / C #:

  1. Ser cortado en una versión de lanzamiento
  2. Terminar un programa de inmediato, sin gracia y tan alto como sea posible.

Python, sin embargo, conscientemente e intencionalmente sacrifica el rendimiento del código para el rendimiento del programador (créalo o no, recientemente obtuve una aceleración de 100 veces al portar algún código de Python a Cython, ¡sin siquiera deshabilitar las comprobaciones de límites!). El código Python se ejecuta en un entorno "seguro" en el que no se puede "romper" completamente su proceso (o un sistema completo) con un segfault / BSoD / bricking imposible de rastrear; lo peor que obtendrá es una excepción no controlada con una carga de información de depuración adjunto, todo con gracia presentado a usted en una forma legible.

  • Lo que implica que el tiempo de ejecución y el código de la biblioteca deben incluir todo tipo de comprobaciones en los momentos apropiados, en todo momento, ya sea "modo de depuración" o no.

Además, el fuerte impacto de Python en proporcionar las fuentes en todo momento (compilación transparente, líneas de origen en traceback, el depurador stock esperando que junto con .pyc ''s sean de algún uso) difumina mucho la línea entre "desarrollo" y "uso". "( setuptools es una de las razones por las setuptools las setuptools de setuptools .egg s crearon una reacción violenta , y por qué pip siempre las instala desempaquetadas : si una está instalada empaquetada, la fuente ya no está disponible y hay problemas con ella, que es diagnosticable).

Combinadas, estas propiedades casi destruyen cualquier caso de uso para el código "solo de depuración".

Y, lo adivinaste, una idea sobre readaptar assert como un cheque de propósito general eventualmente surgió .


Si ser elegante es imposible, ser dramático

Aquí está la versión correcta de tu código:

if filename.endswith(''.jpg''): # convert it to the PNG we want try: filename = convert_jpg_to_png_tmpfile(filename) except PNGCreateError: # Tell the user their jpg was crap print "Your jpg was crap!"

Es un caso válido, en mi humilde opinión cuando:

  1. El error es totalmente, 100% fatal, y enfrentarlo sería demasiado sombrío como para comprenderlo.
  2. La afirmación solo debería fallar si algo hace que cambien las leyes de la lógica.

De lo contrario, lidia con la eventualidad porque puedes verlo venir.

ASSERT == "Esto nunca debería ocurrir en la realidad, y si lo hace, nos rendimos"

Por supuesto, esto no es lo mismo que

#control should never get here

Pero siempre lo hago

#control should never get here #but i''m not 100% putting my money where my mouth #is assert(False)

De esa forma obtengo un buen error. En su ejemplo, usaría la versión if y convertiría el archivo a jpg.