Depuração Python: Domine a instrução `assert` e escreva código impecável

É programador? Se a resposta for afirmativa, a depuração é uma habilidade indispensável, independentemente da linguagem que usa para codificar. Neste artigo, exploraremos como utilizar a instrução assert em Python para realizar uma depuração eficaz.

Durante o desenvolvimento de um projeto, você irá criar diversos módulos, incluindo funções, definições de classes e muito mais. É provável que, em algum momento, se depare com erros ou resultados inesperados devido a falhas na implementação. As instruções assert são ferramentas valiosas para depurar esse tipo de código.

Neste tutorial, vamos detalhar a sintaxe da instrução assert e apresentar exemplos práticos para ilustrar o seu uso. Além disso, abordaremos o conceito de erros de asserção e como podemos empregá-los para identificar e corrigir falhas no código durante o processo de desenvolvimento.

Vamos começar!

Como Utilizar a Instrução Assert em Python

Vamos começar por entender a sintaxe da instrução assert e, em seguida, analisar alguns exemplos de código.

Sintaxe da Instrução Assert

A sintaxe básica da instrução assert em Python é a seguinte:

assert expressão, mensagem

Onde:

  • expressão: É qualquer expressão Python válida que será avaliada. Pode ser uma condição sobre o valor de uma variável, um valor booleano de uma variável, o valor de retorno de uma função, entre outros.
  • Se a expressão for avaliada como True, a instrução assert não gerará nenhum erro ou retorno. Isso indica que o programa está a funcionar corretamente, conforme o esperado.
  • Se a expressão for avaliada como False, uma exceção AssertionError será lançada.
  • mensagem: É uma string opcional. Pode especificar uma mensagem que será exibida no rastreamento (traceback) sempre que uma exceção AssertionError for gerada.

A seguir, vamos explorar alguns exemplos práticos onde a instrução assert nos pode auxiliar a escrever código mais limpo e livre de erros.

Pode encontrar os exemplos de código usados neste tutorial neste gist do GitHub.

Exemplos de Instruções Assert em Python

Considere o seguinte cenário: suponha que você tenha uma variável para representar um desconto no seu código, e deseje garantir que o seu valor nunca exceda um valor máximo predefinido (max_discount). Para garantir isso, pode usar a instrução assert.

Para verificar se por engano a variável de desconto recebeu um valor incorreto, pode adicionar uma declaração. A expressão a ser avaliada será: desconto <= max_discount.

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

Neste caso, discount (20) é menor que max_discount (50). Por conseguinte, a instrução assert não gera qualquer erro.

A Exceção AssertionError

Se a variável desconto receber um valor superior a max_discount, uma exceção AssertionError será lançada.

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

Como já vimos, a instrução assert permite especificar uma string de mensagem opcional. Podemos utilizar essa funcionalidade para fornecer informações de diagnóstico mais descritivas.

Vamos adicionar uma f-string do Python à instrução assert, incluindo os valores das variáveis desconto 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

Como pode ver no exemplo acima, a exceção AssertionError agora inclui os valores das variáveis desconto e max_discount.

Depurando e Testando Funções Python com Assert

Ao definir funções, é possível introduzir inadvertidamente erros (erros lógicos) que impedem o seu correto funcionamento.

Vejamos um exemplo: suponha que estamos a desenvolver um teste e que os alunos têm a opção de responder a uma pergunta extra. Os alunos que responderem à questão extra receberão 10 pontos adicionais no teste. 😄

Considere a seguinte função get_final_score:

  • Recebe uma pontuação atual (score) e um valor booleano bonus como argumentos.
  • Se o aluno respondeu à questão extra (bonus é True), adicionam-se 10 pontos à sua pontuação atual.
  • A função devolve a pontuação final.
def get_final_score(score,bonus):
      if bonus:
          score += 10
      return score

Vamos realizar algumas chamadas à função. Para pontuações de 34 e 40 com o bónus definido como True e False, respetivamente, as pontuações finais são 44 e 40.

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

No entanto, o máximo de pontos no teste é, por exemplo, 50. Se um aluno obtiver 49 pontos e também responder à pergunta extra, a função get_final_score irá calcular a pontuação final como 59.

print(get_final_score(49,True))
  # 59

Tecnicamente, isso é possível. Mas, vamos supor que um aluno não pode obter mais pontos do que o máximo de pontos possíveis para o teste. 🙂

Vamos inicializar uma variável max_score e guardar o valor retornado pela função na variável final_score.

Em seguida, vamos adicionar uma asserção que verifica se final_score é menor ou igual 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

Agora vamos obter uma exceção AssertionError quando chamamos a função get_final_score(47,True):

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

Podemos adicionar uma string informativa à instrução assert:

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

Modificando a Função

Vamos modificar a definição da função get_final_score para corrigir o comportamento inesperado:

  • A função get_final_score também recebe max_score como parâmetro.
  • Verificamos se bonus é True. Se for, adicionamos 10 pontos à variável score.
  • Em seguida, verificamos se score é maior que max_score. Se for, devolvemos max_score.
  • Caso contrário, devolvemos score.

Agora temos a garantia de que a pontuação final é sempre menor ou igual a max_score.

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

Como exercício rápido, escreva algumas asserções para confirmar que a função funciona corretamente.

Uma Nota Sobre a Exceção AssertionError

Embora uma exceção AssertionError ocorra quando a expressão avalia como False, é importante lembrar que não devemos tratar esses erros como exceções comuns. Isso significa que não devemos fazer algo do tipo:

try:
    <fazendo isso>
  except AssertionError:
    <fazer aquilo>

No exemplo anterior da função get_final_score, usamos a asserção para verificar se final_score é menor que max_score. Em seguida, modificamos a definição da função para que não haja erros de asserção.

É para isso que servem as asserções. São verificações da integridade do código e auxiliam na escrita de código mais limpo. O tratamento de exceções, por outro lado, visa antecipar e lidar com erros inesperados em tempo de execução. Geralmente, incluem tipos e valores de entrada inválidos.

Em resumo, deve usar a instrução assert do Python para uma depuração eficaz e não manipular AssertionErrors como exceções.

Conclusão

Este tutorial ajudou-o a compreender como usar a instrução assert em Python. Eis um resumo do que aprendeu:

  • As instruções assert em Python têm a forma de assert expressão. Isso verifica se a expressão é verdadeira. Se não for avaliada como True, uma exceção AssertionError é lançada.
  • Também pode usar a instrução assert com a sintaxe assert expressão, mensagem. Isso irá imprimir a string da mensagem sempre que ocorrer uma exceção AssertionError.
  • Deve ter em mente que não deve implementar um tratamento de exceções para lidar com erros de asserção. Use as asserções como uma ferramenta de depuração útil para verificações do seu código.

Como programador, as asserções auxiliam no processo de depuração. Para garantir que todos os componentes individuais (módulos) do projeto funcionem conforme o esperado, pode aprender a escrever testes unitários em Python.

A seguir, veja esta lista de projetos Python para iniciantes nos quais pode trabalhar.