Gerar exceções

Concluído

Agora que você tem uma boa compreensão dos rastreamentos e do tratamento de exceções, vamos examinar a geração de exceções.

Talvez você já conheça uma situação que pode causar uma condição de erro quando estiver escrevendo o código. Nessas situações, é útil gerar exceções que permitam a outros códigos perceber qual é o problema.

Gerar exceções também pode ajudar na tomada de decisões de outros códigos. Como vimos anteriormente, dependendo do erro, o código pode tomar decisões inteligentes para resolver, solucionar ou ignorar um problema.

Os astronautas limitam o uso de água a cerca de 11 litros por dia. Vamos criar uma função que, dependendo do número de astronautas, pode calcular a quantidade de água que restará após um dia ou mais:

def water_left(astronauts, water_left, days_left):
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    return f"Total water left after {days_left} days is: {total_water_left} liters"

Experimente com cinco astronautas, 100 litros de água restantes e dois dias pela frente:

water_left(5, 100, 2)
'Total water left after 2 days is: -10 liters'

Isso não é muito útil, pois um déficit de litros deve ser considerado um erro. Então, o sistema de navegação pode alertar os astronautas de que não haverá água suficiente para todos em dois dias. Se você for um engenheiro que está programando o sistema de navegação, poderá gerar uma exceção na função water_left() para alertar a condição de erro:

def water_left(astronauts, water_left, days_left):
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    if total_water_left < 0:
        raise RuntimeError(f"There is not enough water for {astronauts} astronauts after {days_left} days!")
    return f"Total water left after {days_left} days is: {total_water_left} liters"

Agora, execute novamente:

water_left(5, 100, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in water_left
RuntimeError: There is not enough water for 5 astronauts after 2 days!

No sistema de navegação, o código para sinalizar o alerta agora pode usar RuntimeError para alertar:

try:
    water_left(5, 100, 2)
except RuntimeError as err:
    alert_navigation_system(err)

A função water_left() também pode ser atualizada para evitar a passagem de tipos sem suporte. Tente passar argumentos que não são inteiros para verificar a saída de erro:

water_left("3", "200", None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in water_left
TypeError: can't multiply sequence by non-int of type 'NoneType'

O erro de TypeError não é muito amigável no contexto do que a função espera. Atualize a função para que ela use TypeError, mas com uma mensagem melhor:

def water_left(astronauts, water_left, days_left):
    for argument in [astronauts, water_left, days_left]:
        try:
            # If argument is an int, the following operation will work
            argument / 10
        except TypeError:
            # TypeError will be raised only if it isn't the right type 
            # Raise the same exception but with a better error message
            raise TypeError(f"All arguments must be of type int, but received: '{argument}'")
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    if total_water_left < 0:
        raise RuntimeError(f"There is not enough water for {astronauts} astronauts after {days_left} days!")
    return f"Total water left after {days_left} days is: {total_water_left} liters"

Agora, tente novamente para obter um erro melhor:

water_left("3", "200", None)
Traceback (most recent call last):
  File "<stdin>", line 5, in water_left
TypeError: unsupported operand type(s) for /: 'str' and 'int'

During handling of the preceding exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in water_left
TypeError: All arguments must be of type int, but received: '3'