Czy pragniesz doskonalić swoje umiejętności programowania w Pythonie? Odkryj, jak „Zen Pythona” może stać się Twoim przewodnikiem w tej podróży.
Python, choć uznawany za język łatwy do opanowania, stawia wyzwanie w kwestii pisania kodu idiomatycznego i łatwego w utrzymaniu, zwłaszcza dla nowicjuszy. PEP-20 wprowadził „Zen Pythona”, zbiór myśli autorstwa Tima Petersa, który uwypukla znaczenie tworzenia kodu zgodnego z najlepszymi praktykami tego języka.
Aby poznać „Zen Pythona”, uruchom interpretera Python REPL i wpisz:
>>> import this
The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those!
Jak widzimy, wiele maksym „Zen Pythona” wydaje się oczywistych. Niektóre z nich należy interpretować w kontekście innych, a niektóre mogą wydawać się sobie przeczyć. Mimo to „Zen Pythona” stanowi interesującą, inspirującą i praktyczną lekturę.
Interpretacja „Zen Pythona”
Uważa się, że „Zen Pythona” składa się z 20 zasad, które powinny kierować programistów Pythona. Na razie jednak istnieje tylko 19 aforyzmów. Przyjrzyjmy się im bliżej.
Piękno jest lepsze niż brzydota.
Ten aforyzm podkreśla potrzebę tworzenia eleganckiego, „pythonicznego” kodu.
Poniższy fragment kodu pozostawia wiele do życzenia:
def square(num): squares = [] for i in range(num): squares.append(i*i) return squares
Funkcja:
- Rozpoczyna działanie z pustą listą,
- Wewnątrz zawiera pętlę, która dodaje elementy na końcu listy,
- Na koniec zwraca listę.
Chociaż funkcja ta jest poprawna pod względem funkcjonalnym, brakuje jej „pythonicznego” charakteru i jest trudna w utrzymaniu.
Można ją zapisać w znacznie bardziej elegancki sposób, wykorzystując generatory. Oto odpowiednik funkcji generatora:
def square(num): for i in range(num): yield i*i
A jeszcze lepiej, można zastosować wyrażenie generatora:
num = ... squares = (i*i for i in range(num))
Jawne jest lepsze niż ukryte.
Podczas pisania kodu, staraj się nie zmuszać innych programistów i użytkowników do domyślania się intencji lub domyślnego zachowania kodu. Bądź klarowny. Rozważmy przykład importowania symboli za pomocą gwiazdki:
from some_module import * # import z symbolem wieloznacznym from some_other_module import * result = some_function() # skąd się to wzięło?
Unikaj używania symboli wieloznacznych, kiedy tylko to możliwe. Są niejednoznaczne i nieefektywne. Podczas importowania funkcji i klas z innych modułów bądź konkretny:
from some_module import this_function # import jawny result = this_function() # teraz już wiemy.
Proste jest lepsze niż złożone.
Ten aforyzm sugeruje, że powinniśmy dążyć do prostoty w kodzie i unikać niepotrzebnych komplikacji. Na przykład, jeśli chcesz odwrócić ciąg, możesz spróbować zaimplementować poniższe rozwiązanie rekurencyjne:
def reverse_string(my_string): if my_string == "": return my_string else: return reverse_string(my_string[1:]) + my_string[:1]
Chociaż to rozwiązanie działa, jest zbytecznie skomplikowane, biorąc pod uwagę, że istnieją prostsze i bardziej „pythoniczne” sposoby na osiągnięcie tego samego rezultatu.
Oto podejście z wykorzystaniem krojenia ciągów:
>>> rev_string = my_string[::-1] >>> rev_string 'nohtyP'
A tutaj wykorzystujemy wbudowane metody i funkcje:
>>> rev_string = ''.join(reversed(my_string)) >>> rev_string 'nohtyP'
Złożone jest lepsze niż skomplikowane.
Co zatem przekazuje ten kolejny aforyzm „Zen Pythona”?
Odwrócenie ciągu w Pythonie to bardzo prosta operacja. W praktyce jednak możemy potrzebować bardziej skomplikowanej logiki. Oto dosyć prosty przykład:
Załóżmy, że potrzebujesz połączyć się z bazą danych:
- Najpierw musisz przeanalizować plik konfiguracyjny toml, aby pobrać informacje o konfiguracji bazy danych.
- Musisz mieć zainstalowany łącznik bazy danych.
- Następnie możesz zdefiniować funkcję, która połączy się z bazą danych, przewidując błędy połączenia, wdrażając obsługę błędów i wiele więcej.
- Wreszcie, po połączeniu się z bazą danych, możesz wysłać zapytanie.
Chociaż to zadanie nadal jest proste, wymaga bardziej skomplikowanej logiki niż odwrócenie ciągu. Nie oznacza to jednak, że musi być skomplikowane. Nadal możesz efektywnie wykorzystać funkcje wbudowanych modułów i zorganizować kod w sposób, który będzie zrozumiały i dostępny dla innych programistów.
Płaskie jest lepsze niż zagnieżdżone.
Struktura płaska jest prostsza do analizy i zrozumienia niż struktura zagnieżdżona. Podczas pracy nad projektem możesz ulec pokusie odizolowania funkcjonalności, tworząc osobne moduły. Jednak nadmierna granularność może być przesadą.
Często zdarza się, że trzeba wyjść poza płaską strukturę. Jednak nawet jeśli zagnieżdżanie jest konieczne, staraj się je ograniczyć do minimum.
Oto przykład:
from db_info.config.actions.parse.parse_config import parse_toml # zbyt skomplikowane! ... from db_config.parse_config import parse_toml # znacznie lepiej! ...
Rzadkie jest lepsze niż gęste.
Jeśli dopiero zaczynasz przygodę z programowaniem, możesz ulec pokusie nadużywania niektórych funkcji języka. Na przykład, wyrażenia listowe są bardzo przydatne w Pythonie, ale tylko wtedy, gdy używasz ich w odpowiednich sytuacjach.
Spójrz na poniższe wyrażenie listowe:
prices_dict = {'melons':40,'apples':70,'berries':55} items = [(fruit,price) for fruit in prices_dict.keys() if fruit.startswith('m') for price in prices_dict.values() if price < 50] print(items) # Wynik: [('melons', 40)]
To wyrażenie jest zbyt gęste i trudne do zrozumienia. W tym przypadku użycie równoważnej pętli for z wyrażeniami warunkowymi byłoby bardziej czytelne. Samo zrozumienie istoty wyrażenia listowego może być wyzwaniem. 🙂
Liczy się czytelność.
Zawsze powinieneś pisać czytelny kod. Oto kilka prostych wskazówek, które pomogą Ci poprawić czytelność kodu:
- Stosuj opisowe nazwy zmiennych.
- Dodawaj dokumentację do funkcji i klas.
- Komentuj kod w razie potrzeby.
- Dodawaj wskazówki typów dla argumentów i zwracanych typów funkcji.
Wyjątkowe przypadki nie są wystarczająco wyjątkowe, aby łamać zasady.
Powinieneś – w miarę możliwości – stosować się do zasad języka i zalecanych najlepszych praktyk.
Ale czy zawsze jest to możliwe? Nie, dlatego mamy kolejny aforyzm.
Chociaż praktyczność wygrywa z czystością.
To uzupełnienie poprzedniego aforyzmu. Chociaż zaleca się przestrzeganie zasad języka, w niektórych przypadkach odstępstwo od nich może być uzasadnione.
Błędy nigdy nie powinny przechodzić po cichu.
W Pythonie błędy wykonawcze są czymś powszechnym. Dobrą praktyką jest zawsze obsługa błędów i unikanie ich wyciszania w ramach szybkiego obejścia problemu.
Powinieneś przewidzieć i wdrożyć odpowiednią obsługę błędów dla różnych typów błędów:
try: # wykonanie operacji except ErrorType1: # obsługa błedu ErrorType1 except ErrorType2: # obsługa błedu ErrorType2 ...
Unikaj nagich i ogólnych wyjątków. Nowsze wersje Pythona (od Pythona 3.11) obsługują łańcuchy wyjątków i grupy wyjątków, co umożliwia bardziej zaawansowaną obsługę wyjątków.
Chyba że zostaną jawnie wyciszone.
To rozwinięcie poprzedniego aforyzmu. Jeśli w projekcie konieczne jest wyciszenie błędu, należy to zrobić w sposób jawny.
Na przykład, podczas łączenia się z bazą danych możesz napotkać błąd operacyjny z powodu nieprawidłowych ustawień konfiguracyjnych. Spróbuj połączyć się, korzystając z niestandardowej konfiguracji. Jeśli wystąpi błąd operacyjny, wykorzystaj domyślną konfigurację i ponownie spróbuj połączyć się z bazą danych.
try: # łączenie przy użyciu niestandardowej konfiguracji except OperationalError: # łączenie przy użyciu domyślnej konfiguracji
W obliczu niejednoznaczności, odrzuć pokusę zgadywania.
Ten aforyzm z „Zen Pythona” jest oczywisty. W przypadku wątpliwości nie zgaduj. Uruchom kod i przeanalizuj wynik. Następnie, w zależności od tego, czy uzyskasz pożądane zachowanie, popraw czytelność lub zmodyfikuj logikę.
Rozważmy prosty przykład z krotką boolean:
>>> True, True == (True, True) (True, False) >>> True, (True == (True, True)) (True, False) >>> (True, True) == (True, True) True
Powinien istnieć jeden – i najlepiej tylko jeden – oczywisty sposób.
Dla każdego zadania, powinien istnieć jeden i tylko jeden zalecany, „pythoniczny” sposób jego wykonania. Jednak dla każdego problemu możemy znaleźć wiele rozwiązań.
Nawet w prostym przykładzie odwracania ciągu widzieliśmy rozwiązanie rekurencyjne, z wykorzystaniem krojenia ciągu oraz metodę join().
Jest to również swego rodzaju wewnętrzny żart, biorąc pod uwagę niespójne użycie myślników em. Zwykle używamy myślników bez spacji lub z odstępem zarówno z przodu, jak i z tyłu.
Możemy z tego wywnioskować, że aforyzm, który podkreśla, że powinien istnieć jeden i tylko jeden „pythoniczny” sposób robienia rzeczy, sam w sobie może być zapisany na więcej niż dwa sposoby.
Chociaż ten sposób może nie być na początku oczywisty, chyba że jesteś Holendrem.
Ten żartobliwy akcent odnosi się do Guido van Rossuma, twórcy Pythona, który pochodzi z Holandii. (Najbardziej) „pythoniczny” sposób na wykonanie zadania, często przychodzi naturalnie tylko tym, którzy tworzyli ten język.
Dlatego programiści potrzebują doświadczenia i uczenia się na błędach, aby lepiej wykorzystywać możliwości tego języka.
Teraz jest lepsze niż nigdy.
Podobnie jak wiele innych aforyzmów z „Zen Pythona”, również ten można interpretować na wiele sposobów.
Jedna z interpretacji jest taka, że jako programista, często zwlekasz z rozpoczęciem kodowania projektu. Zamiast czekać z zaplanowaniem najdrobniejszych szczegółów projektu, lepiej jest zacząć go teraz.
Inna interpretacja może być taka, że kod, który działa w skończonej liczbie kroków i kończy się, jest często lepszy niż kod, który zawiera błędy i utknął w nieskończonej pętli.
Chociaż nigdy nie jest często lepsze niż *teraz*.
Ten aforyzm wydaje się przeczyć poprzedniemu. Chociaż lepiej nie zwlekać, warto przemyśleć problem i odpowiednio zaprojektować kod.
Kodowanie modułu bez wcześniejszego zastanowienia się, który jest pełen wad i antywzorców, to zły pomysł. Taki kod jest trudny do refaktoryzacji i wdrożenia poprawek.
Jeśli implementacja jest trudna do wyjaśnienia, jest to zły pomysł.
Każdą logikę, bez względu na jej złożoność, zawsze można zaimplementować w sposób łatwy do wyjaśnienia i zrozumienia.
Jeśli implementacja jest trudna do wyjaśnienia, prawdopodobnie jest to niepotrzebnie skomplikowane. Kod można zmodyfikować lub zrefaktoryzować, aby ułatwić jego śledzenie.
Jeśli implementacja jest łatwa do wyjaśnienia, to może być dobry pomysł.
Jest to powiązane z poprzednim aforyzmem i również jest oczywiste. Jeśli implementację można wytłumaczyć w prosty sposób, prawdopodobnie jest to dobry pomysł.
Ponieważ kod, którego implementację można opisać w prostych słowach, z dużym prawdopodobieństwem będzie czytelny, łatwy do śledzenia i nie będzie zbytnio skomplikowany.
Przestrzenie nazw to świetny pomysł – korzystajmy z nich częściej!
W Pythonie dostęp do obiektów w danym zakresie uzyskuje się za pomocą ich nazw w przestrzeni nazw. Na przykład możesz utworzyć klasę i użyć jej jako szablonu do tworzenia instancji klasy. Teraz wszystkie zmienne instancji będą znajdować się w przestrzeni nazw instancji.
Dzięki temu możemy używać obiektów o tej samej nazwie, unikając konfliktów, ponieważ znajdują się one w różnych przestrzeniach nazw. Jednak korzystaj z nich tylko wtedy, gdy jest to konieczne i upewnij się, że nie naruszasz prostoty i czytelności kodu.
Podsumowanie
To wszystko w tym artykule! Mam nadzieję, że ten przewodnik pomógł Ci zrozumieć, jak „Zen Pythona” kładzie nacisk na styl kodu i dobre praktyki programowania w Pythonie. Im więcej kodujesz, tym lepszy się stajesz.
Jeśli pragniesz dowiedzieć się, jak pisać zwięzły i czytelny kod, przeczytaj artykuł o jednowierszowcach w języku Python.