Disabilita le asserzioni in Python


Risposte:


80

Come disabilito le asserzioni in Python?

Esistono più approcci che influiscono su un singolo processo, l'ambiente o una singola riga di codice.

Dimostro ciascuno.

Per l'intero processo

L'uso del -Oflag (O maiuscola) disabilita tutte le istruzioni di asserzione in un processo.

Per esempio:

$ python -Oc "assert False"

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

Nota che per disabilitare intendo anche che non esegue l'espressione che lo segue:

$ 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

Per l'ambiente

Puoi anche usare una variabile d'ambiente per impostare questo flag.

Ciò influenzerà ogni processo che utilizza o eredita l'ambiente.

Ad esempio, in Windows, impostare e quindi cancellare la variabile d'ambiente:

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 stesso in Unix (usando set e unset per le rispettive funzionalità)

Unico punto nel codice

Continui la tua domanda:

se un'asserzione fallisce, non voglio che generi un AssertionError, ma che continui.

Se si desidera che il codice non venga eseguito, è possibile intercettare o assicurarsi che il flusso di controllo non raggiunga l'asserzione, ad esempio:

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

oppure puoi rilevare l'errore di asserzione:

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

che stampa:

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

e continuerai dal punto in cui hai gestito il file AssertionError.

Riferimenti

Dalla assertdocumentazione :

Un'affermazione assert come questa:

assert expression #, optional_message

È equivalente a

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

E,

la variabile incorporata __debug__è Truein circostanze normali, Falsequando viene richiesta l'ottimizzazione (opzione della riga di comando -O).

e inoltre

Le assegnazioni a __debug__sono illegali. Il valore per la variabile incorporata viene determinato all'avvio dell'interprete.

Dai documenti di utilizzo:

-O

Attiva le ottimizzazioni di base. Questo cambia l'estensione del nome del file per i file compilati (bytecode) da .pyc a .pyo. Vedi anche PYTHONOPTIMIZE.

e

PYTHONOPTIMIZE

Se è impostato su una stringa non vuota, è equivalente a specificare l' -Oopzione. Se impostato su un numero intero, equivale a specificare -Opiù volte.


sarebbe possibile saltare il codice che fallisce in caso di "Single point in code"? Ho provato a impostare __debug__False ma non è consentito.
Matthijs

1
@ Matthijs puoi assicurarti che il flusso di controllo non lo raggiunga (ad esempio if False: assert False) o puoi rilevare l'errore di asserzione. Queste sono le tue scelte. Aggiornata la risposta per rispondere alla tua domanda.
Aaron Hall

Grazie per la risposta, ma non ancora del tutto a cosa stavo pensando. Vorrei disattivare afferma all'interno di una funzione durante l'esecuzione, idealmente con una sorta di contesto gestore: asserzione viene valutata: foo()e asserzioni SPEGNIMENTO: with skip_assertion(): foo(). Il vantaggio di questo è che non devo aggiungere un altro flag alla funzione
Matthijs

2
È possibile riscrivere il bytecode della funzione, riscrivere l'AST o riscrivere la funzione stessa. (manualmente o in modo programmatico, per entrambi). Riscrivere l'AST sarebbe probabilmente l'approccio più affidabile (sostituire "semplicemente" gli Assertoggetti con gli Passoggetti). Un gestore di contesto non funzionerebbe direttamente per questo, ma potresti avere una sorta di meccanismo che utilizza funzioni decorate in quel modo. Indipendentemente da ciò, non lo consiglio. Sospetto che il motivo per cui lo desideri è che stai chiamando un codice che non controlli e ottieni AssertionErrors. In tal caso, probabilmente dovrai trovare una soluzione diversa.
Aaron Hall

60

Chiama Python con il flag -O:

test.py:

assert(False)
print 'Done'

Produzione:

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

9
Affermare non è una funzione, quindi le parentesi sono superflue.
Aaron Hall

15

Entrambe le due risposte già fornite sono valide (chiama Python con -Oo -OOsulla riga di comando).

Ecco la differenza tra loro:

  • -OAttiva le ottimizzazioni di base. Questo cambia l'estensione del nome del file per i file compilati (bytecode) da .pyc a .pyo.

  • -OOElimina le stringhe di documentazione oltre alle -Oottimizzazioni.

(Dalla documentazione di Python )



3

Si dovrebbe NON disattivare (la maggior parte) affermazioni. Catturano errori imprevisti quando l'attenzione è altrove. Vedere la regola 5 in "Il potere di dieci" .

Invece, custodisci alcuni costosi controlli di asserzione con qualcosa del tipo:

import logging
logger = logging.getLogger(__name__)

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

Un modo per mantenere le asserzioni importanti e consentire l' assertottimizzazione delle istruzioni è aumentarle all'interno di un'istruzione di selezione:

if foo_is_broken():
    raise AssertionError('Foo is broken!')

1
//, Il problema è, tuttavia, che l'istruzione aggiunge ancora complessità ciclomatica e la gestione degli errori dovrebbe gestire il resto?
Nathan Basanese

1
Le affermazioni che verrebbero salvaguardate come sopra sono chiamate costose che rallentano significativamente l'esecuzione. Per alcuni algoritmi, i controlli di questo tipo possono richiedere ordini di grandezza più lunghi dell'intero programma. Pensa di eseguire un'implementazione ingenua ma più semplice (quindi meno probabile che contenga errori) dello stesso algoritmo per verificarne la correttezza. O un controllo mediante enumerazione esaustiva di qualcosa che è fuori discussione per il normale funzionamento.
Ioannis Filippidis

Non vedo molti problemi con la leggibilità, perché una tale dichiarazione non aggiunge annidamenti al codice. Estrarlo come una chiamata di funzione può spostarlo fuori mano, se questo è un problema (e mi aspetto che un tale refactoring riduca la complessità ciclomatica). In ogni caso, la complessità ciclomatica non dovrebbe governare i controlli di sicurezza.
Ioannis Filippidis

2

L'esecuzione in modalità ottimizzata dovrebbe farlo:

python -OO module.py
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.