Risposte:
La assert
dichiarazione esiste in quasi tutti i linguaggi di programmazione. Aiuta a rilevare i problemi nelle prime fasi del programma, in cui la causa è chiara, anziché successivamente come effetto collaterale di qualche altra operazione.
Quando lo fai...
assert condition
... stai dicendo al programma di testare quella condizione e di innescare immediatamente un errore se la condizione è falsa.
In Python, è approssimativamente equivalente a questo:
if not condition:
raise AssertionError()
Provalo nella shell di Python:
>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
Le asserzioni possono includere un messaggio opzionale e puoi disabilitarle quando esegui l'interprete.
Per stampare un messaggio se l'asserzione non riesce:
assert False, "Oh no! This assertion failed!"
Do Non utilizzare parentesi per chiamare assert
come una funzione. È una dichiarazione. Se lo fai assert(condition, message)
, eseguirai il file assert
con una (condition, message)
tupla come primo parametro.
Per quanto riguarda la loro disabilitazione, quando si esegue python
in modalità ottimizzata, dove si __debug__
trova False
, le istruzioni assert verranno ignorate. Basta passare la -O
bandiera:
python -O script.py
Vedere qui per la documentazione pertinente.
if not condition: raise AssertError()
, perché dovrei usare assert? Ci sono condizioni in cui affermare che è meglio se non essere una forma più breve di if not condition
affermazione?
if
). Leggi i documenti per maggiori informazioni :)
assert
, ma dopo aver letto tutte le risposte, non ho ottenuto assolutamente nulla di quello che voglio!
Fai attenzione alle parentesi. Come è stato sottolineato sopra, in Python 3 assert
è ancora un'affermazione , quindi per analogia con print(..)
, si può estrapolare lo stesso a assert(..)
o raise(..)
non si dovrebbe.
Questo è importante perché:
assert(2 + 2 == 5, "Houston we've got a problem")
non funzionerà, diversamente
assert 2 + 2 == 5, "Houston we've got a problem"
Il motivo per cui il primo non funzionerà è che bool( (False, "Houston we've got a problem") )
valuta True
.
Nella dichiarazione assert(False)
, queste sono solo parentesi ridondanti in giro False
, che valutano il loro contenuto. Ma con assert(False,)
le parentesi ora sono una tupla e una tupla non vuota viene valutata True
in un contesto booleano.
assert (2 + 2 = 5), "Houston we've got a problem"
dovrebbe essere ok, sì?
assert (2 + 2 = 5), "Houston we've got a problem"
non funzionerà ... ma non ha nulla a che fare con l'affermazione assert, che va bene. La tua condizione non funzionerà perché non è una condizione. Manca un secondo =
.
Come hanno notato altre risposte, assert
è simile a lanciare un'eccezione se una determinata condizione non è vera. Una differenza importante è che le istruzioni assert vengono ignorate se si compila il codice con l'opzione di ottimizzazione -O
. La documentazione afferma che assert expression
può essere meglio descritto come equivalente a
if __debug__:
if not expression: raise AssertionError
Questo può essere utile se vuoi testare a fondo il tuo codice, quindi rilasciare una versione ottimizzata quando sei felice che nessuno dei tuoi casi di asserzione fallisca - quando l'ottimizzazione è attiva, la __debug__
variabile diventa False e le condizioni smetteranno di essere valutate. Questa funzione può anche sorprenderti se fai affidamento sugli asserti e non ti rendi conto che sono scomparsi.
if Not Error: raise Exception(“ this is a error”)
? In questo modo, il programma mostrerà comunque l'origine dell'errore, quando l'utente lo esegue ..
assert
dichiarazione? Il presupposto qui è che quando il programma viene rilasciato all'utente finale, si sta utilizzando il flag -O, assumendo quindi che tutti i bug siano stati rimossi. Pertanto, qualsiasi errore o arresto anomalo del programma è dovuto all'input nel programma valido secondo il contratto, ma non può essere gestito dal programma. Quindi dovrebbe avvisare l'utente in quanto tale.
L'obiettivo di un'asserzione in Python è informare gli sviluppatori su errori irrecuperabili in un programma.
Le asserzioni non intendono segnalare condizioni di errore previste, come "file non trovato", in cui un utente può intraprendere azioni correttive (o semplicemente riprovare).
Un altro modo di osservarlo è dire che le asserzioni sono autocontrolli interni nel tuo codice. Funzionano dichiarando alcune condizioni come impossibili nel tuo codice. Se queste condizioni non valgono, significa che c'è un bug nel programma.
Se il tuo programma è privo di bug, queste condizioni non si verificheranno mai. Ma se si verifica uno di questi , il programma si arresterà in modo anomalo con un errore di asserzione che indica esattamente quale condizione "impossibile" è stata attivata. Questo rende molto più facile rintracciare e correggere i bug nei tuoi programmi.
Ecco un riassunto di un tutorial sulle affermazioni di Python che ho scritto:
L'affermazione di asserzione di Python è un aiuto per il debug, non un meccanismo per la gestione degli errori di runtime. L'obiettivo dell'utilizzo delle asserzioni è consentire agli sviluppatori di trovare più rapidamente la probabile causa alla radice di un bug. Un errore di asserzione non dovrebbe mai essere generato a meno che non ci sia un bug nel tuo programma.
assert
Dichiarazione molto utile per capire e quando usarla. Sto cercando di comprendere una serie di termini che hai introdotto nell'articolo.
assert store.product_exists(product_id), 'Unknown product id'
non è una buona pratica, perché se il debug è disattivato, user
anche se non admin
sarà possibile eliminare il prodotto. Consideri assert user.is_admin()
un unrecoverable
errore? Perché questo non è un self-check
?
assert statement
, non puoi price
essere considerato un input dell'utente? Perché consideri assert user.is_admin()
la convalida dei dati ma non assert price
?
Altri ti hanno già fornito link alla documentazione.
Puoi provare quanto segue in una shell interattiva:
>>> assert 5 > 2
>>> assert 2 > 5
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
builtins.AssertionError:
La prima affermazione non fa nulla, mentre la seconda solleva un'eccezione. Questo è il primo suggerimento: gli asserti sono utili per verificare le condizioni che dovrebbero essere vere in una determinata posizione del codice (di solito, l'inizio (condizioni preliminari) e la fine di una funzione (postcondizioni)).
Le asserzioni sono in realtà fortemente legate alla programmazione per contratto, che è una pratica ingegneristica molto utile:
Da documenti:
Assert statements are a convenient way to insert debugging assertions into a program
Qui puoi leggere di più: http://docs.python.org/release/2.5.2/ref/assert.html
L'affermazione assert ha due forme.
La forma semplice assert <expression>
, è equivalente a
if __debug__:
if not <expression>: raise AssertionError
La forma estesa assert <expression1>, <expression2>
, è equivalente a
if __debug__:
if not <expression1>: raise AssertionError, <expression2>
Le asserzioni sono un modo sistematico per verificare che lo stato interno di un programma sia come previsto dal programmatore, con l'obiettivo di catturare i bug. Vedi l'esempio sotto.
>>> number = input('Enter a positive number:')
Enter a positive number:-1
>>> assert (number > 0), 'Only positive numbers are allowed!'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Only positive numbers are allowed!
>>>
Ecco un semplice esempio, salvalo nel file (diciamo b.py)
def chkassert(num):
assert type(num) == int
chkassert('a')
e il risultato quando $python b.py
Traceback (most recent call last):
File "b.py", line 5, in <module>
chkassert('a')
File "b.py", line 2, in chkassert
assert type(num) == int
AssertionError
se l'affermazione dopo assert è vera, il programma continua, ma se l'affermazione dopo assert è falsa, il programma dà un errore. Semplice come quella.
per esempio:
assert 1>0 #normal execution
assert 0>1 #Traceback (most recent call last):
#File "<pyshell#11>", line 1, in <module>
#assert 0>1
#AssertionError
La assert
dichiarazione esiste in quasi tutti i linguaggi di programmazione. Aiuta a rilevare i problemi nelle prime fasi del programma, in cui la causa è chiara, anziché successivamente come effetto collaterale di qualche altra operazione. Si aspettano sempre una True
condizione.
Quando fai qualcosa come:
assert condition
Stai dicendo al programma di testare quella condizione e di innescare immediatamente un errore se è falso.
In Python, assert
espressione , equivale a:
if __debug__:
if not <expression>: raise AssertionError
È possibile utilizzare l'espressione estesa per passare un messaggio facoltativo :
if __debug__:
if not (expression_1): raise AssertionError(expression_2)
Provalo nell'interprete Python:
>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
Ci sono alcuni avvertimenti da vedere prima di usarli principalmente per coloro che ritengono di alternare tra le dichiarazioni assert
e if
. Lo scopo da utilizzare assert
è in occasioni in cui il programma verifica una condizione e restituisce un valore che dovrebbe arrestare immediatamente il programma invece di prendere un modo alternativo per bypassare l'errore:
Come avrai notato, la assert
dichiarazione utilizza due condizioni. Quindi, non usare le parentesi per inglobarle come una per un ovvio consiglio. Se lo fai come:
assert (condition, message)
Esempio:
>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
Eseguirai il simbolo assert
with a (condition, message)
che rappresenta una tupla come primo parametro, e questo accade perché la tupla non vuota in Python è sempreTrue
. Tuttavia, puoi farlo separatamente senza problemi:
assert (condition), "message"
Esempio:
>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.
Se ti stai chiedendo riguardo a quando utilizzare la assert
dichiarazione. Prendi un esempio usato nella vita reale:
* Quando il tuo programma tende a controllare ogni parametro inserito dall'utente o qualsiasi altra cosa:
def loremipsum(**kwargs):
kwargs.pop('bar') # return 0 if "bar" isn't in parameter
kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())
* Un altro caso è in matematica quando 0 o non positivo come coefficiente o costante su una determinata equazione:
def discount(item, percent):
price = int(item['price'] * (1.0 - percent))
print(price)
assert (0 <= price <= item['price']),\
"Discounted prices cannot be lower than 0 "\
"and they cannot be higher than the original price."
return price
* o anche un semplice esempio di implementazione booleana:
def true(a, b):
assert (a == b), "False"
return 1
def false(a, b):
assert (a != b), "True"
return 0
La massima importanza è non fare affidamento assert
sull'istruzione per eseguire l'elaborazione dei dati o la convalida dei dati poiché questa istruzione può essere disattivata sull'inizializzazione di Python con -O
o -OO
flag - che significa rispettivamente valore 1, 2 e 0 (come predefinito) - o PYTHONOPTIMIZE
variabile di ambiente .
Valore 1:
* le affermazioni sono disabilitate;
* i file bytecode sono generati usando .pyo
extension invece di .pyc
;
* sys.flags.optimize
è impostato su 1 ( True
);
* e, __debug__
è impostato su False
;
Valore 2: disabilita un'altra roba
* i docstring sono disabilitati;
Pertanto, l'utilizzo assert
dell'istruzione per convalidare una sorta di dati previsti è estremamente pericoloso, implicando persino alcuni problemi di sicurezza. Quindi, se è necessario convalidare alcune autorizzazioni, ti consiglio raise AuthError
invece. Come precondizionato efficace, un assert
è comunemente usato dai programmatori su librerie o moduli che non hanno un utente interagire direttamente.
Come sintetizzato sinteticamente sul Wiki C2 :
Un'asserzione è un'espressione booleana in un punto specifico di un programma che sarà vera a meno che non ci sia un bug nel programma.
È possibile utilizzare assert
un'istruzione per documentare la comprensione del codice in un determinato punto del programma. Ad esempio, è possibile documentare ipotesi o garanzie su input (precondizioni), stato del programma (invarianti) o output (postcondizioni).
Se la tua affermazione dovesse mai fallire, questo è un avviso per te (o per il tuo successore) che la tua comprensione del programma era sbagliata quando l'hai scritta e che probabilmente contiene un bug.
Per ulteriori informazioni, John Regehr ha un meraviglioso post sul blog sull'uso delle asserzioni , che si applica anche assert
all'istruzione Python .
Python assert è fondamentalmente un aiuto per il debug che verifica le condizioni per l'autocontrollo interno del codice. Assert semplifica notevolmente il debug quando il codice arriva in casi limite impossibili. Afferma di controllare quei casi impossibili.
Diciamo che esiste una funzione per calcolare il prezzo dell'articolo dopo lo sconto:
def calculate_discount(price, discount):
discounted_price = price - [discount*price]
assert 0 <= discounted_price <= price
return discounted_price
qui, il prezzo scontato non può mai essere inferiore a 0 e superiore al prezzo effettivo. Quindi, nel caso in cui la suddetta condizione venga violata, l'asserzione genera un errore di asserzione, che aiuta lo sviluppatore a identificare che era accaduto qualcosa di impossibile.
Spero che sia d'aiuto :)
assert
è utile in un contesto di debug, ma non deve essere fatto affidamento al di fuori di un contesto di debug.
La mia breve spiegazione è:
assert
genera AssertionError
se espressione è falsa, altrimenti continua semplicemente il codice, e se c'è una virgola qualunque essa sia AssertionError: whatever after comma
, e codificare è come:raise AssertionError(whatever after comma)
Un tutorial correlato su questo:
https://www.tutorialspoint.com/python/assertions_in_python.htm
assert
, ma non quando usare (o non usare) un assert
; notando anche che un assert
può essere disabilitato se __debug__
è False
utile.
In Pycharm, se lo usi assert
insieme a isinstance
per dichiarare il tipo di un oggetto, ti permetterà di accedere ai metodi e agli attributi dell'oggetto genitore mentre stai codificando, si completerà automaticamente.
Ad esempio, supponiamo che self.object1.object2
sia un MyClass
oggetto.
import MyClasss
def code_it(self):
testObject = self.object1.object2 # at this point, program doesn't know that testObject is a MyClass object yet
assert isinstance(testObject , MyClasss) # now the program knows testObject is a MyClass object
testObject.do_it() # from this point on, PyCharm will be able to auto-complete when you are working on testObject
Come scritto in altre risposte, le assert
dichiarazioni vengono utilizzate per verificare lo stato del programma in un determinato punto.
Non ripeterò quanto detto su messaggio associato, parentesi o -O
opzione e __debug__
costante. Controlla anche il documento per informazioni di prima mano. Mi concentrerò sulla tua domanda: a che serve assert
? Più precisamente, quando (e quando no) si dovrebbe usare assert
?
Le assert
istruzioni sono utili per il debug di un programma, ma scoraggiate a controllare l'input dell'utente. Uso la seguente regola empirica: mantenere le asserzioni per rilevare una situazione che non dovrebbe accadere . Un input dell'utente potrebbe essere errato, ad es. Una password troppo corta, ma questo non è un caso che non dovrebbe accadere . Se il diametro di un cerchio non è grande il doppio del suo raggio, in questo caso non dovrebbe accadere .
L'utilizzo più interessante, secondo me, assert
è ispirato dalla
programmazione per contratto descritta da B. Meyer in [Costruzione di software orientato agli oggetti] (
https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction% 2C_2nd_Edition
) e implementato nel [linguaggio di programmazione Eiffel] (
https://en.wikipedia.org/wiki/Eiffel_(programming_language) ). Non è possibile emulare completamente la programmazione per contratto utilizzando la assert
dichiarazione, ma è interessante mantenere l'intento.
Ecco un esempio Immagina di dover scrivere una head
funzione (come la [ head
funzione in Haskell] (
http://www.zvon.org/other/haskell/Outputprelude/head_f.html )). La specifica che viene fornita è: "se l'elenco non è vuoto, restituisce il primo elemento di un elenco". Guarda le seguenti implementazioni:
>>> def head1(xs): return xs[0]
E
>>> def head2(xs):
... if len(xs) > 0:
... return xs[0]
... else:
... return None
(Sì, questo può essere scritto come return xs[0] if xs else None
, ma non è questo il punto) .
Se l'elenco non è vuoto, entrambe le funzioni hanno lo stesso risultato e questo risultato è corretto:
>>> head1([1, 2, 3]) == head2([1, 2, 3]) == 1
True
Quindi, entrambe le implementazioni sono (spero) corrette. Differiscono quando si tenta di prendere l'elemento principale di un elenco vuoto:
>>> head1([])
Traceback (most recent call last):
...
IndexError: list index out of range
Ma:
>>> head2([]) is None
True
Ancora una volta, entrambe le implementazioni sono corrette, perché nessuno dovrebbe passare un elenco vuoto a queste funzioni (siamo fuori specifica ). È una chiamata errata, ma se fai una chiamata del genere, tutto può succedere. Una funzione genera un'eccezione, l'altra restituisce un valore speciale. Il più importante è: non possiamo fare affidamento su questo comportamento . Se xs
è vuoto, funzionerà:
print(head2(xs))
Ma questo andrà in crash il programma:
print(head1(xs))
Per evitare alcune sorprese, vorrei sapere quando sto passando argomenti inaspettati a una funzione. In altre parole: vorrei sapere quando il comportamento osservabile non è affidabile, perché dipende dall'implementazione, non dalle specifiche. Certo, posso leggere le specifiche, ma i programmatori non sempre leggono attentamente i documenti.
Immagina se avessi un modo per inserire la specifica nel codice per ottenere il seguente effetto: quando viola la specifica, ad esempio passando un elenco vuoto a head
, ricevo un avviso. Sarebbe di grande aiuto per scrivere un programma corretto (cioè conforme alle specifiche). Ed è qui che assert
entra in scena:
>>> def head1(xs):
... assert len(xs) > 0, "The list must not be empty"
... return xs[0]
E
>>> def head2(xs):
... assert len(xs) > 0, "The list must not be empty"
... if len(xs) > 0:
... return xs[0]
... else:
... return None
Ora abbiamo:
>>> head1([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty
E:
>>> head2([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty
Nota che head1
genera un AssertionError
, non un IndexError
. Questo è importante perché AssertionError
non si verifica alcun errore di runtime: segnala una violazione delle specifiche. Volevo un avviso, ma ho ricevuto un errore. Fortunatamente, posso disabilitare il controllo (usando l' -O
opzione), ma a mio rischio e pericolo. Lo farò un incidente è davvero costoso e spero per il meglio. Immagina che il mio programma sia incorporato in un'astronave che attraversa un buco nero. Disabiliterò le asserzioni e spero che il programma sia abbastanza robusto da non bloccarsi il più a lungo possibile.
Questo esempio riguardava solo le precondizioni, sia che tu possa usare assert
per controllare le postcondizioni (il valore di ritorno e / o lo stato) e gli invarianti (stato di una classe). Nota che il controllo di postcondizioni e invarianti con assert
può essere complicato:
Non avrai qualcosa di sofisticato come Eiffel, ma puoi comunque migliorare la qualità generale di un programma.
Per riassumere, l' assert
affermazione è un modo conveniente per rilevare una situazione che non dovrebbe accadere . Le violazioni delle specifiche (ad esempio il passaggio di un elenco vuoto a head
) sono di prima classe, ciò non dovrebbe accadere . Pertanto, sebbene la assert
dichiarazione possa essere utilizzata per rilevare qualsiasi situazione imprevista, è un modo privilegiato per garantire che la specifica sia rispettata. Dopo aver inserito le assert
istruzioni nel codice per rappresentare la specifica, possiamo sperare che tu abbia migliorato la qualità del programma perché verranno riportati argomenti errati, valori di ritorno errati, stati errati di una classe ...
format: assert Expression [, argomenti] Quando assert incontra un'istruzione, Python valuta l'espressione. Se l'istruzione non è vera, viene sollevata un'eccezione (assertionError). Se l'asserzione non riesce, Python utilizza ArgumentExpression come argomento per AssertionError. Le eccezioni AssertionError possono essere rilevate e gestite come qualsiasi altra eccezione utilizzando l'istruzione try-tranne, ma se non gestite, termineranno il programma e produrranno un traceback. Esempio:
def KelvinToFahrenheit(Temperature):
assert (Temperature >= 0),"Colder than absolute zero!"
return ((Temperature-273)*1.8)+32
print KelvinToFahrenheit(273)
print int(KelvinToFahrenheit(505.78))
print KelvinToFahrenheit(-5)
Quando viene eseguito il codice sopra riportato, produce il seguente risultato:
32.0
451
Traceback (most recent call last):
File "test.py", line 9, in <module>
print KelvinToFahrenheit(-5)
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!
def getUser(self, id, Email):
user_key = id and id or Email
assert user_key
Può essere utilizzato per garantire che i parametri vengano passati nella chiamata di funzione.
if not user_key: raise ValueError()
ultimi 2 paragrafi qui: wiki.python.org/moin/UsingAssertionsEffectively
assert
non deve essere utilizzato per la convalida dell'input perché la convalida verrà eliminata se lo __debug__
è False
. Anche l'uso di asserzioni per scopi di non debug può indurre le persone a catturare i messaggi risultanti AssertionError
, il che può rendere il debug più difficile invece che minore.
>>>this_is_very_complex_function_result = 9
>>>c = this_is_very_complex_function_result
>>>test_us = (c < 4)
>>> #first we try without assert
>>>if test_us == True:
print("YES! I am right!")
else:
print("I am Wrong, but the program still RUNS!")
I am Wrong, but the program still RUNS!
>>> #now we try with assert
>>> assert test_us
Traceback (most recent call last):
File "<pyshell#52>", line 1, in <module>
assert test_us
AssertionError
>>>
Fondamentalmente il significato della parola chiave assert è che se la condizione non è vera, allora attraverso un assertionerror altrimenti continua ad esempio in Python.
code-1
a=5
b=6
assert a==b
PRODUZIONE:
assert a==b
AssertionError
code-2
a=5
b=5
assert a==b
PRODUZIONE:
Process finished with exit code 0
assert
, ma non risponde quando usare (o non usare) un assert
.