Podstawy obsługi wyjątków cz.1

Błędy, które ujawniają się podczas wykonania programu i nie są błędami składniowymi należą do tzw. wyjątków. Lista wyjątków jest dosyć pokaźna >>zobacz<<

Wyjątki te możemy obsługiwać, umieszczając kod, który może spowodować wyjątek w bloku try tzn.

try:
    # Tutaj umieszczamy kod, który może wywołać wyjątek lub wyjątki

a kod, który ma obsłużyć dany wyjątek w bloku except (odpowiednik javowego catch) tzn.

except:
    # Tutaj umieszczamy kod obsługi wyjątku

Bardziej przydatne jest reagowanie na pojawienie się konkretnych wyjątków niż obsługa wszystkich “zbiorczo”. Sama instrukcja except bez podania nazwy klasy błędu może być przydatna, jeśli chcemy przechwycić wyjątek, który nie został jeszcze obsłużony przez wcześniejszy blok except np.

except ZeroDivisionError:
    # Tutaj umieszczamy kod obsługujący wyjątek ZeroDivisionError

except NameError:
    # Tutaj umieszczamy kod obsługujący wyjątek NameError

except:
    # Tutaj wyłapujemy pozostałe, nieobsłużone wyjątki

>>Część druga<<

Podstawy obsługi wyjątków cz.2

Oczywiście możemy także stosować składnię, w której opis wyjątku jest przypisywany do zmiennej i możemy go potem wyświetlić w procedurze obsługi np.

except NameError as e:
    print('Message:', e)

Można tworzyć wspólną procedurę obsługi dla kilku wyjątków umieszczając nazwy klas w krotce np.

except (ZeroDivisionError, NameError):
    # Tutaj umieszczamy procedurę obsługi tych dwóch wyjątków

Na co należy zwrócić uwagę to aby wyjątki stanowiące klasy potomne w hierarchii klas wyjątków były obsługiwane przed klasami z których dziedziczą. Błędna kolejność będzie skutkować tym, że wyjątek obsłuży bardziej ogólna procedura, która była pierwsza w kolejności tzn.

except Exception:
    print('It catches all exceptions!')
except NameError:
    print('NameError exception')

W powyższym przykładzie wyjątek NameError zostanie obsłużony przez procedurę zawartą w pierwszym bloku except. Pomimo wystąpienia wyjątku NameError zostanie wyświetlony napis: It catches all exceptions!, a procedura obsługująca konkretnie ten wyjątek (i wyświetlająca w tym przypadku napis NameError exception) nie zostanie wykonana.

>>Część trzecia<<

Podstawy obsługi wyjątków cz.3

Należy jeszcze wspomnieć o opcjonalnym bloku else, który zostaje wykonany tylko, gdy w powiązanym bloku try nie wystąpił wyjątek tzn.

  • jeśli blok else występuje to musi być umieszczony po blokach except
  • może być tylko jeden blok else (lub wcale)

Blok else używamy jeśli nie chcemy aby pewien fragment kodu był zawarty w bloku try. Gdyby cały kod umieścić zamiast tego w bloku try, to przyczyna wywołania wyjątku byłaby potencjalnie trudniejsza do zlokalizowania.

Kolejnym opcjonalnym blokiem jest blok finally, który zostaje wykonany niezależnie od tego, czy wystąpił wyjątek, czy nie:

  • jeśli blok finally występuje, to musi być umieszczony po blokach except (i else – jeśli ten występuje)
  • może być tylko jeden blok finally (lub wcale)

Blok finally używa się głównie do czynności porządkowych np. do zwalniania dostępu do zewnętrznych zasobów.

Proste narzędzie do wyświetlania kalendarza

Program ten jest prostym odpowiednikiem konsolowego narzędzia cal, które wyświetla w konsoli kalendarz dla podanego roku i miesiąca.

Jeśli nie podano argumentów, domyślnie drukuje kalendarz dla bieżącego roku i miesiąca. /screenshot/

#!/usr/bin/env python

from datetime import datetime

from calendar import monthrange, weekheader, weekday

from sys import stdout


def cal(year=datetime.today().year, month=datetime.today().month):
    """
    Prints month calendar for given year and month.
    """

    this_year = year
    this_month = month

    # number of all days in month
    days_in_month = monthrange(this_year, this_month)[1]

    # which week day is the first day of month
    first_day_of_month = weekday(this_year, this_month, 1)

    # prints header of calendar (width 5)
    print(weekheader(5))

    # positioning loop
    # for proper position of the first element
    for i in range(first_day_of_month):
        stdout.write(6 * ' ')

    i = 1
    while i <= days_in_month:
        stdout.write(' {:>2}   '.format(i))
        # new line if sunday
        if weekday(this_year, this_month, i) == 6:
            print('')
        i += 1
    print('')

if __name__ == '__main__':
    cal()