Deshabilitar aserciones en Python

Respuestas:

75

¿Cómo desactivo las afirmaciones en Python?

Hay varios enfoques que afectan a un solo proceso, el entorno o una sola línea de código.

Demuestro cada uno.

Para todo el proceso

El uso de la -Obandera (O mayúscula) deshabilita todas las declaraciones de aserción en un proceso.

Por ejemplo:

$ python -Oc "assert False"

$ python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Tenga en cuenta que por deshabilitar me refiero a que tampoco ejecuta la expresión que le sigue:

$ python -Oc "assert 1/0"

$ python -c "assert 1/0"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Por el medio ambiente

También puede usar una variable de entorno para establecer esta bandera.

Esto afectará a todos los procesos que utilizan o heredan el entorno.

Por ejemplo, en Windows, configurar y luego borrar la variable de entorno:

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError
C:\>SET PYTHONOPTIMIZE=TRUE

C:\>python -c "assert False"

C:\>SET PYTHONOPTIMIZE=

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Lo mismo en Unix (usando set y unset para la funcionalidad respectiva)

Punto único en el código

Continúas tu pregunta:

si una aserción falla, no quiero que arroje un AssertionError, sino que continúe.

Si desea que el código no se ejecute, puede asegurarse de que el flujo de control no llegue a la aserción, por ejemplo:

if False:
    assert False, "we know this fails, but we don't get here"

o puede detectar el error de aserción:

try:
    assert False, "this code runs, fails, and the exception is caught"
except AssertionError as e:
    print(repr(e))

que imprime:

AssertionError('this code runs, fails, and the exception is caught')

y continuará desde el punto en que manejó el AssertionError.

Referencias

De la assertdocumentación :

Una afirmación como esta:

assert expression #, optional_message

Es equivalente a

if __debug__:
    if not expression: raise AssertionError #(optional_message)

Y,

la variable incorporada __debug__está Trueen circunstancias normales, Falsecuando se solicita la optimización (opción de línea de comando -O).

y además

Las asignaciones a __debug__son ilegales. El valor de la variable incorporada se determina cuando se inicia el intérprete.

De los documentos de uso:

-O

Active las optimizaciones básicas. Esto cambia la extensión del nombre de archivo para archivos compilados (código de bytes) de .pyc a .pyo. Consulte también PYTHONOPTIMIZAR.

y

PITONOPTIMIZAR

Si se establece en una cadena no vacía, equivale a especificar la -Oopción. Si se establece en un número entero, equivale a especificar -Ovarias veces.

Aaron Hall
fuente
¿Sería posible omitir el código que falla en el caso de 'Punto único en el código'? Intenté configurarlo __debug__en False pero eso no está permitido.
Matthijs
1
@Matthijs puede asegurarse de que el flujo de control no lo alcance (por ejemplo if False: assert False) o puede detectar el error de afirmación. Esas son tus elecciones. Se actualizó la respuesta para abordar su pregunta.
Aaron Hall
Gracias por la respuesta, pero aún no del todo en lo que estaba pensando. Me gustaría desactivar afirma dentro de una función en tiempo de ejecución, a ser posible con algún tipo de gestor de contexto: se evalúa la afirmación: foo()y afirmaciones Desconexión: with skip_assertion(): foo(). El beneficio de esto es que no tengo que agregar otra bandera en la función
Matthijs
2
Puede reescribir el código de bytes de la función, reescribir el AST o reescribir la función en sí. (manual o programáticamente, para cualquiera). Reescribir el AST probablemente sería el enfoque más confiable ("simplemente" reemplazar Assertobjetos con Passobjetos). Un administrador de contexto no funcionaría directamente para eso, pero podría tener algún tipo de mecanismo que usara funciones decoradas de esa manera. Independientemente, no lo recomiendo. Sospecho que su razón para querer hacerlo es que está llamando a un código que no controla y obteniendo AssertionErrors. Si es así, probablemente necesite encontrar una solución diferente.
Aaron Hall
59

Llame a Python con la bandera -O:

test.py:

assert(False)
print 'Done'

Salida:

C:\temp\py>C:\Python26\python.exe test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    assert(False)
AssertionError

C:\temp\py>C:\Python26\python.exe -O test.py
Done
Mark Rushakoff
fuente
8
Afirmar no es una función, por lo que los parens son superfluos.
Aaron Hall
15

Las dos respuestas ya dadas son válidas (llame a Python con -Oo -OOen la línea de comando).

Aquí está la diferencia entre ellos:

  • -OActive las optimizaciones básicas. Esto cambia la extensión del nombre de archivo para archivos compilados (código de bytes) de .pyc a .pyo.

  • -OODescarte las cadenas de documentos además de las -Ooptimizaciones.

(De la documentación de Python )

Michael Currie
fuente
7

Utilizar python -O:

$ python -O
>>> assert False
>>> 
John Millikin
fuente
3

NO debe deshabilitar (la mayoría) de las afirmaciones. Detectan errores inesperados cuando la atención está en otra parte. Consulte la Regla 5 en "El poder de diez" .

En su lugar, proteja algunas comprobaciones de afirmaciones caras con algo como:

import logging
logger = logging.getLogger(__name__)

if logger.getEffectiveLevel() < logging.DEBUG:
    ok = check_expensive_property()
    assert ok, 'Run !'

Una forma de mantener afirmaciones importantes y permitir que las assertdeclaraciones se optimicen es elevándolas dentro de una declaración de selección:

if foo_is_broken():
    raise AssertionError('Foo is broken!')
Ioannis Filippidis
fuente
1
//, ¿El problema es, sin embargo, que la declaración aún se suma a la complejidad ciclomática y el manejo de errores debería manejar el resto?
Nathan Basanese
1
Las afirmaciones que se protegerían como las anteriores son llamadas costosas que ralentizan significativamente la ejecución. Para algunos algoritmos, las comprobaciones de este tipo pueden tardar varios órdenes de magnitud más que el programa completo. Piense en ejecutar una implementación ingenua pero más simple (por lo que es menos probable que contenga errores) del mismo algoritmo para verificar la corrección. O una verificación mediante una enumeración exhaustiva de algo que está fuera de cuestión para el funcionamiento normal.
Ioannis Filippidis
No veo mucho problema con la legibilidad, porque tal declaración no agrega anidamiento al código. Extraerlo como una llamada de función puede moverlo fuera del camino, si eso es un problema (y espero que tal refactorización debería reducir la complejidad ciclomática). En cualquier caso, la complejidad ciclomática no debería regir los controles de seguridad.
Ioannis Filippidis
2

Ejecutar en modo optimizado debería hacerlo:

python -OO module.py
FogleBird
fuente