Debug efficace con l’istruzione Python Assert

Sei un programmatore? In tal caso, il debugging è un’abilità essenziale, indipendentemente dal linguaggio in cui stai codificando. In questo articolo imparerai come utilizzare l’istruzione assert in Python per un debugging efficace.

Quando lavori a un progetto, definirai più moduli. Ciò include funzioni, definizioni di classe e altro. E probabilmente ti imbatterai in errori o risultati imprevisti a causa di un bug nell’implementazione. Le dichiarazioni di asserzione sono utili per il debug di tale codice.

In questo tutorial impareremo la sintassi per utilizzare l’istruzione assert seguita da esempi di codice per vederla in azione. Vedremo anche quali sono gli errori di asserzione e come possiamo usarli per correggere gli errori nel codice durante lo sviluppo.

Cominciamo!

Come utilizzare l’istruzione Assert in Python

Impareremo la sintassi per utilizzare l’istruzione assert, quindi procederemo alla codifica di alcuni esempi.

Sintassi dell’istruzione Assert

Iniziamo con la sintassi per usare l’istruzione assert in Python:

assert expression, message

Qui,

  • espressione è qualsiasi espressione Python valida da valutare. Questa può essere una condizione sul valore della variabile, il valore di verità della variabile, il valore restituito da una funzione e altro.
  • Finché l’espressione restituisce True, l’istruzione assert non genera un errore né restituisce nulla. Ciò indica che il programma funziona come previsto.
  • Se l’espressione non è più True, viene sollevata un’eccezione AssertionError.
  • message è una stringa facoltativa. È possibile specificare un messaggio che viene visualizzato nel trace back ogni volta che viene sollevata un’eccezione AssertionError.

Successivamente, procediamo a codificare alcuni esempi in cui l’istruzione assert può aiutarci a scrivere codice più pulito e privo di bug.

È possibile trovare gli esempi di codice usati in questo tutorial in questo GitHub Gist.

Esempi di istruzioni Assert di Python

Considera il seguente esempio. Supponi di avere una variabile di sconto nel tuo codice. Ma vorresti che il suo valore fosse sempre minore o uguale a max_discount.

Per verificare di non aver impostato accidentalmente la variabile sconto su un valore, puoi aggiungere un’asserzione. L’espressione da valutare è: discount <= max_discount.

>>> max_discount = 50
>>> discount = 20
>>> assert discount <= max_discount

Qui lo sconto (20) è inferiore a max_discount (50). Quindi l’istruzione assert non genera alcun errore.

L’eccezione AssertionError

Se la variabile discount è impostata su un valore maggiore di max_discount, viene sollevata un’eccezione AssertionError.

>>> discount = 75
>>> assert discount <= max_discount
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Sappiamo che l’istruzione assert ci consente anche di specificare una stringa di messaggio facoltativa.

Usiamo anche una stringa di messaggio che fornisce informazioni diagnostiche più descrittive. All’istruzione assert, aggiungiamo una f-string Python che contiene anche i valori di discount e max_discount.

>>> assert discount <= max_discount, f"discount should be at most {max_discount}; got discount = {discount}"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: discount should be at most 50; got discount = 75

Come visto nella cella di output precedente, l’eccezione AssertionError ora include i valori delle variabili discount e max_discount.

Debug e test delle funzioni Python con Assert

Quando definisci le funzioni, a volte potresti inavvertitamente introdurre bug (errori logici) che impediranno alla tua funzione di funzionare come previsto.

Facciamo un esempio. Supponiamo che ci sia un test in una classe e agli studenti venga data la possibilità di tentare una domanda bonus. Ogni studente che tenta la domanda bonus otterrà 10 punti aggiuntivi nel test. 😄

Considera la seguente funzione get_final_score:

  • Comprende un punteggio corrente, un punteggio e un bonus booleano.
  • Se uno studente ha risposto alla domanda bonus, il bonus booleano è Vero e ottiene 10 punti in più rispetto al punteggio attuale.
  • La funzione restituisce quindi il punteggio finale.
def get_final_score(score,bonus):
    if bonus:
        score += 10
    return score

Facciamo alcune chiamate alla funzione. Vediamo che per punteggi di 34 e 40 con bonus impostato su Vero e Falso, i punteggi finali sono rispettivamente 44 e 40.

print(get_final_score(34,True))
# 44
print(get_final_score(40,False))
# 40

Tuttavia, il punteggio massimo del test è, diciamo, 50. Quindi, se uno studente ottiene un punteggio di 49 e ha anche risposto alla domanda bonus, la funzione get_final_score calcolerà felicemente il punteggio finale in 59.

print(get_final_score(49,True))
# 59

Tecnicamente, è possibile. Ma supponiamo che uno studente non possa ottenere più del punteggio massimo possibile per il test. 🙂

Quindi inizializziamo una variabile max_score. E cattura il punteggio restituito dalla funzione nella variabile final_score.

Successivamente aggiungiamo un’asserzione che verifica se final_score è inferiore a max_score.

def get_final_score(score,bonus):
    if bonus:
        score += 10
    return score

final_score = get_final_score(47,True)
max_score = 50

assert final_score <= max_score

Ora otteniamo un’eccezione AssertionError per la chiamata di funzione get_final_score(47,True):

Traceback (most recent call last):
  File "main.py", line 17, in <module>
    assert final_score <= max_score
AssertionError

Ora aggiungiamo una stringa f descrittiva all’istruzione assert di Python:

assert final_score <= max_score,f"final_score should be at most {max_score}; got {final_score}"
Traceback (most recent call last):
  File "main.py", line 17, in <module>
    assert final_score <= max_score,f"final_score should be at most {max_score}; got {final_score}"
AssertionError: final_score should be at most 50; got 57

Modifica della funzione

Torniamo indietro e modifichiamo la definizione della funzione get_final_score per correggere il comportamento imprevisto:

  • Anche la funzione get_final_score accetta max_score come parametro.
  • Controlliamo se il bonus è vero. Se True, aggiungiamo 10 punti alla variabile score.
  • Quindi, controlliamo se score è maggiore di max_score. In tal caso, restituiamo max_score.
  • Altrimenti, restituiamo il punteggio.

Ora ci siamo assicurati che il punteggio finale sia sempre minore o uguale a max_score.

def get_final_score(score,bonus,max_score):
    if bonus:
        score += 10
    if score > max_score:
        return max_score
    return score

Come esercizio rapido, scrivi alcune asserzioni per confermare che la funzione ora funziona come previsto.

Una nota sull’eccezione AssertionError

Sebbene si verifichi un’eccezione AssertionError quando l’espressione restituisce False, dovremmo ricordarci di non gestire tali errori come eccezioni. Significa che non dovremmo fare qualcosa del genere:

try:
    <doing this>
except AssertionError:
    <do this>

Nell’esempio precedente su get_final_score, abbiamo usato l’asserzione per controllare se final_score è minore di max_score. Quindi abbiamo modificato la definizione della funzione in modo tale che non vi siano errori di asserzione.

Ecco a cosa servono le asserzioni. Sono controlli di integrità per il codice e aiutano a scrivere codice più pulito. La gestione delle eccezioni, d’altra parte, consiste nell’anticipare e gestire gli errori imprevisti in fase di esecuzione. Questi includono spesso tipi e valori di input non validi.

Per riassumere, dovresti usare l’istruzione assert di Python per un debug efficace e non gestire AssertionErrors come eccezioni.

Conclusione

Questo tutorial ti ha aiutato a capire come usare l’istruzione assert in Python. Ecco un riepilogo di ciò che hai imparato:

  • Le dichiarazioni assert di Python (asserzioni) assumono la forma assert expression. Questo controlla se l’espressione è vera. Se non restituisce True, viene sollevata un’eccezione AssertionError.
  • Puoi anche usare assert con la sintassi assert expression, message. Questo stamperà la stringa del messaggio ogni volta che si verifica un’eccezione AssertionError.
  • È necessario ricordare di non implementare la gestione delle eccezioni per gestire gli errori di asserzione. E usa le asserzioni come utile strumento di debug per i controlli di integrità del tuo codice.

In qualità di sviluppatore, le asserzioni ti aiutano con il debug. Per garantire che tutti i singoli componenti (moduli) del progetto funzionino come previsto, puoi imparare a scrivere unit test in Python.

Successivamente, dai un’occhiata a questo elenco di progetti Python per principianti su cui puoi lavorare.