Przechwytywanie wyjątków w Pythonie

Przechwytywanie wyjątków w Pythonie
doskanoness
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 81
0

Mam pytanie, mianowicie chcę zczytać inta i w przypadku kiedy operacja się nie powiedzie przechwycić wyjątek ValueError, z tą różnicą że zamiast domyślnego komunikatu invalid literal for int() with base 10: 'regrg' chcę przekazać do konstruktora ValueError własny komunikat. Czy w poniższym kodzie dobrze to robię? Mam na myśli zagnieżdżoną instrukcję try wewnątrz instrukcji try w funkcji read_date. Chcę wiedzieć czy ta dobra jest dobra, czy istnieją sprytniejsze sposoby na to.

Przykładowy kod:

Kopiuj
def read_date():
    valid = False
    year = None
    era = None
    while not valid:
        try:
            print('Enter a year in the format year [BCE|CE]. Note that part BCE|CE is optional.')
            print("If era won't be specified, then default value will be CE.")
            date = input('> ')
            if date.isnumeric():
                year = date
                era = Era.CE
            else:
                year = date.split()[0]
                era = date.split()[-1]
                if era == 'BCE':
                    era = Era.BCE
                elif era == 'CE':
                    era = Era.CE
                else:
                    raise ValueError('Error: invalid era. Valid choices are BCE and CE.')
            try:
                year = int(year)
            except ValueError:
                raise ValueError('Error: year must be an integer.')
            if year < 1:
                raise ValueError('Error: year must be greater than 0.')
        except ValueError as e:
            print(e)
        else:
            valid = True
    return HistoricalDate(year=year, era=era)
Spearhead
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1007
1

Używa się konstrukcji raise nowy_wyjatek from stary_wyjatek. Porównaj komunikaty:

Kopiuj
>>> def foo():
...     raise ValueError("...")
... 
>>> 
>>> try:
...     foo()
... except ValueError:
...     raise ValueError("???")
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in foo
ValueError: ...

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: ???
>>>
>>>
>>>
>>> try:
...     foo()
... except ValueError as e:
...     raise ValueError("???") from e
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in foo
ValueError: ...

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: ???
doskanoness
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 81
0

To masz na myśli?

Kopiuj
def read_date():
    valid = False
    year = None
    era = None
    while not valid:
        try:
            print('Enter a year in the format year [BCE|CE]. Note that part BCE|CE is optional.')
            print("If era won't be specified, then default value will be CE.")
            date = input('> ')
            if date.isnumeric():
                year = date
                era = Era.CE
            else:
                year = date.split()[0]
                era = date.split()[-1]
                if era == 'BCE':
                    era = Era.BCE
                elif era == 'CE':
                    era = Era.CE
                else:
                    raise ValueError('Error: invalid era. Valid choices are BCE and CE.')
            try:
                year = int(year)
            except ValueError as e:
                raise ValueError('Error: year must be an integer.') from e
            if year < 1:
                raise ValueError('Error: year must be greater than 0.')
        except ValueError as e:
            print(e)
        else:
            valid = True
    return HistoricalDate(year=year, era=era)

Tak jest dobrze?

doskanoness
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 81
0

Mam jeszcze pytanie, co sądzisz o napisaniu scentralizowanego systemu obsługi wyjątków?

Arthan
  • Rejestracja: dni
  • Ostatnio: dni
0

Niektórzy chwalą i zalecają takie podejście :)
https://owasp.org/www-project-proactive-controls/v3/en/c10-errors-exceptions
Positive Advice > "Manage exceptions in a centralized manner to avoid duplicated try/catch blocks in the code. Ensure that all unexpected behavior is correctly handled inside the application."

vpiotr
  • Rejestracja: dni
  • Ostatnio: dni
0
doskanoness napisał(a):

Mam jeszcze pytanie, co sądzisz o napisaniu scentralizowanego systemu obsługi wyjątków?

Zcentralizowana obsługa jest niezbędna, ale zwykle to za mało.

Zamiast robić w jednym miejscu try/catch dla każdego wyjątku:

  • bazujesz wszystkie swoje wyjątki na Exception
  • w swoich modułach które udostępniasz innym jako API
    • dajesz jeden bazowy exception per moduł bazujący na Exception - ułatwia to obsługę błędów innym
    • w każdym unikalnym wypadku stosujesz nową klasę exception bazującą na bazowym exception modułu
  • w swoich modułach prywatnych możesz używać standardowych exception lub bazujących na standardowych

Więcej o tym w poradzie 87 w Effective Python i https://doughellmann.com/posts/python-exception-handling-techniques/

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.