
Błędy w kodzie to coś, z czym każdy programista prędzej czy później musi się zmierzyć. Niezależnie od tego, czy piszemy krótki program automatyzujący codzienną pracę, czy rozbudowujemy dużą aplikację webową o kolejny feature, prędzej czy później pojawi się sytuacja, której nie przewidzieliśmy. I właśnie w tym momencie zaczyna się prawdziwe projektowanie oprogramowania. To, czy błędy sparaliżują nam pracę – nieistotne, czy powstałe z winy użytkownika, czy też wadliwego kodu – zależy od tego jak dobrze zaprojektowaliśmy sobie obsługę błędów w kodzie. Python dzięki swojemu systemowi wyjątków (Exceptions), pozwala na sprawne wyłapywanie błędów określonego rodzaju jak i projektowanie własnych, dopasowanych do określonych potrzeb.
Proste wykrywanie błędów za pomocą try-except
Załóżmy, że nasz użytkownik wypełnia formularz podając nam swoje dane, a wśród nich np. wiek zapisywany w zmiennej wiek_uzytkownika. Naturalnie oczekujemy, iż wiek będzie liczbą całkowitą. Skoro tak, to wywołanie na nim funkcji int() nie powinno nam zwrócić błędu:
Jeśli chcemy się przygotować na błąd i jego odpowiednią obsługę warto sprawdzić jaki błąd zwróci nam Python wpisując do Pythonowego interpretera np.:
Błąd, którego poszukujemy to ValueError. Teraz możemy wykorzystać try-except celem „wyłapania” go. W bloku try dajemy porcję kodu, który próbujemy wykonać – w normalnej sytuacji wykona się on normalnie. Z kolei w bloku except projektujemy co ma się wydarzyć jeśli dany rodzaj błędu zostanie wykryty, np. wyświetlimy informację że wiek musi być liczbą:
Można dodawać nowe bloki except wyłapywujące różne rodzaje błędów, np. przyjmimy od użytkownika liczbę w zmiennej liczba i użyjmy jej do dzielenia. Wiele rzeczy może pójść nie tak:
Czasem chcemy się „ubezpieczyć” ekstra przed nieprzewidzianym błędem, służy do tego uniwersalne Exception – ono wyłapie każdy rodzaj błędu:
Nie powinno się jednak go nadużywać – jeśli oczekujemy konkretnych rodzajów błędów to zawsze warto wyłapywać je najpierw.
Projektowanie własnych błędów
Python ma cakłiem pokaźną listę wbudowanych błędów: [Python Built-in Exceptions]. Niestety, w praktyce projektując własne aplikacje bardzo szybko będziemy potrzebować własnych błędów uruchamiających się w odpowiednich sytuacjach. Załóżmy, że prowadzimy sklep spożywczy. Jeśli klient zdecyduje się na zakup tytoniu lub alkoholu musimy zweryfikować czy ma przynajmniej 18 lat, zaprojektujemy więc błąd jako klasę:
Nasza klasa dziedziczy po klasie Exception, więc jest kompatybilna z mechanizmem try-except i Python „wie”, że Under18Error to rodzaj błędu. W konstruktorze klasy (__init__) ustawiamy domyślny komunikat w message gdyby program nie podał żadnego od siebie. Na koniec wywołujemy konstruktor klasy bazowej (czyli Exception) z naszym komunikatem. Pozostaje wpiąć nasz błąd w działający program – błąd wywołamy komendą raise Under18Error. Załóżmy że wiek klienta mamy już w zmiennej wiek_klienta:
Możemy dodawać odpowiednie komunikaty, jeśli np. jest w dziale z tytoniem, to zamienimy naszą pierwotną komendę raise komendą:
Łatanie dziur logicznych w kodzie
Ostatnią rzeczą, o której warto pamiętać jest upewnianie się, że nasze bramki logiczne obsługują wszystkie scenariusze. Załóżmy, że nasza aplikacja przetwarza faktury z Polski i Niemiec, naturalnie w kodzie znajdzie się więc kod podobny do tego poniżej:
Nawet jeśli nie planujemy procesować innych faktur, to warto obsłużyć tutaj sytuację w której zmienna event['kraj'] przyjmie inną wartość – być może za rok rozszerzymy działalność np. o Litwę. W aplikacji liczącej tysiące linijek kodu ciężko będzie wyłapać gdzie „znikają” litewskie faktury, wystarczy dodać coś w stylu:
Niekoniecznie chroni nas to przed wszystkimi błędami – mogło się zdarzyć że program próbował pobrać faktury z systemu, ale akurat wszystkie były już przeprocesowane i zwrócił nam pustą tabelkę, a kluczowa zmienna nie została spopulowana. W takim przypadku otrzymamy KeyError przy próbie odwołania się do event['kraj']. Żeby temu zapobiec warto przed blokiem if-else dodać dodatkową weryfikację, np.:
Tutaj EmptyTableError byłby naszym zaprojektowanym błędem, który niekoniecznie kończyłby pracę całego programu. Program mógłby działać dalej, dzięki odpowiedniemu zastosowaniu try-except:
Jeśli chcesz usłyszeć więcej o programowaniu w Pythonie, projektowaniu błędów, czy pracy z ETL i innymi technologiami Data Engineera, koniecznie sprawdź nasz kurs Data Engineer na infoShare Academy!

Autor
Data Engineer @ CBRE | Python | PySpark | AWS | PostgreSQL | Terraform | CI/CD | Docker | Tableau
Jestem Data Engineerem z ponad 7-letnim doświadczeniem. Przeszedłem ścieżkę od analityka i BI Developera (Excel, Tableau) do obecnej roli opartej na Pythonie, SQL i AWS. Doświadczenie w pracy z biznesem pozwala mi patrzeć na dane kompleksowo. Obecnie skupiam się na backendzie, a pasję do nauki realizuję na bootcampach, gdzie wyjaśniam skomplikowane technologie prostymi słowami.



