Pisanie kodu Pythona z pomocą PEP8, część 1.
Zalecane zasady pisania pięknego kodu w Pythonie opisane w PEP8.
Wstęp
PEP8, czasami pisany jako PEP 8 lub PEP-8, to dokument zawierający wytyczne i najlepsze praktyki dotyczące pisania kodu Pythona. Został on napisany w 2001 roku przez Guido van Rossuma, Barry’ego Warsawa i Alyssę Coghlan. Głównym celem PEP8 jest poprawa czytelności i spójności kodu Pythona. Link do źródła PEP8.
PEP to skrót od Python Enhancement Proposal i istnieje wiele PEP-ów. Dokumenty te opisują przede wszystkim nowe funkcje proponowane dla języka Python, ale niektóre PEP koncentrują się również na projektowaniu i stylu, i mają służyć jako zasób dla społeczności. PEP 8 jest jednym z tych PEP skupiających się na stylu.
W tym samouczku omówione zostaną kluczowe wytyczne określone w PEP 8. Omówione zostaną tematy związane z programowaniem dla początkujących i średnio zaawansowanych. Bardziej zaawansowane tematy można poznać czytając pełną dokumentację PEP8. PEP 8 istnieje po to, by poprawić czytelność kodu Pythona. Ale dlaczego czytelność jest tak ważna? Dlaczego pisanie czytelnego kodu jest jedną z głównych zasad języka Python, zgodnie z Zen of Python?
Jak powiedział Guido van Rossum, “kod jest czytany znacznie częściej niż jest pisany”.
Możesz spędzić kilka minut lub cały dzień, pisząc fragment kodu do przetwarzania uwierzytelniania użytkownika. Kiedy już go napiszesz, nigdy nie napiszesz go ponownie. Ale na pewno będziesz musiał go ponownie przeczytać. Ten fragment kodu może pozostać częścią projektu, nad którym pracujesz. Za każdym razem, gdy wrócisz do tego pliku, będziesz musiał pamiętać, co robi ten kod i dlaczego go napisałeś, więc czytelność ma znaczenie. Zapamiętanie, co robi dany fragment kodu kilka dni lub tygodni po jego napisaniu może być trudne. Jeśli zastosujesz się do PEP 8, możesz być pewien, że dobrze nazwałeś swoje zmienne. Będziesz wiedział, że dodałeś wystarczająco dużo białych znaków, aby łatwiej było śledzić logiczne kroki w kodzie. Dobrze też skomentowałeś swój kod. Wszystko to sprawi, że kod będzie bardziej czytelny i łatwiej będzie do niego wrócić. Jeśli jesteś początkujący, przestrzeganie zasad PEP 8 może sprawić, że nauka Pythona stanie się o wiele przyjemniejszym zadaniem. Jeśli masz większe doświadczenie w pisaniu kodu w Pythonie, być może będziesz musiał współpracować z innymi. Pisanie czytelnego kodu jest tutaj kluczowe. Inne osoby, które być może nigdy wcześniej cię nie spotkały lub nie widziały twojego stylu kodowania, będą musiały przeczytać i zrozumieć twój kod. Posiadanie wytycznych, których przestrzegasz i które rozpoznajesz, ułatwi innym czytanie twojego kodu.
Jawne jest lepsze niż ukryte.
Kiedy piszesz kod Pythona, musisz nazwać wiele rzeczy: zmienne, funkcje, klasy, pakiety itd. Wybieranie sensownych nazw zaoszczędzi ci później czasu i energii. Będziesz w stanie dowiedzieć się z nazwy, co reprezentuje dana zmienna, funkcja lub klasa. Unikniesz również używania potencjalnie mylących nazw, które mogą powodować błędy trudne do debugowania. Jedną z sugestii jest, aby nigdy nie używać nazw składających się z pojedynczych liter l, O lub I, ponieważ mogą one być mylone z 1 i 0, w zależności od kroju pisma używanego przez programistę. Przykładem może być poniższy kod, w którym pojedynczej literze O przypisano wartość 2:
O = 2 # ❌ Nie zalecane
Może to wyglądać tak, jakbyś próbował przypisać 2 do zera. Podczas gdy wykonanie takiego przypisania nie jest możliwe w Pythonie i spowoduje błąd składni, użycie niejednoznacznej nazwy zmiennej, takiej jak O, może sprawić, że kod będzie bardziej zagmatwany i trudniejszy do odczytania.
Style nazewnictwa
Poniższa tabela przedstawia niektóre z popularnych stylów nazewnictwa w kodzie Pythona i sytuacje, w których należy ich używać:
Typ | Konwencja nazewnictwa | Przykłady |
---|---|---|
Funkcja | Użyj słowa lub słów pisanych małymi literami. Oddziel słowa podkreślnikami, aby poprawić czytelność. | function , python_function |
Zmienna | Używaj pojedynczych małych liter, słów lub wyrazów. Oddzielaj słowa podkreślnikami, aby poprawić czytelność. | x , var , python_zmienna |
Klasa | Każde słowo należy rozpoczynać wielką literą. Nie oddzielaj słów podkreśleniami. Styl ten nazywany jest wielbłądzim (camel case) lub pascalowym (Pascal case). | Model , PythonClass |
Metoda | Słowa należy pisać małymi literami. Oddzielaj słowa podkreślnikami, aby poprawić czytelność. | class_method , method |
Stała | Używaj wielkich pojedynczych liter, słów lub wyrazów. Oddzielaj słowa podkreślnikami, aby poprawić czytelność. | CONSTANT , PYTHON_CONSTANT , PYTHON_LONG_CONSTANT |
Moduł | Używaj krótkich słów pisanych małymi literami. Oddzielaj słowa podkreślnikami, aby poprawić czytelność. | module.py , python_module.py |
Pakiet | Używaj krótkich słów pisanych małymi literami. Nie oddzielaj słów podkreślnikami. | package , pythonpackage |
Oto niektóre z powszechnych konwencji nazewnictwa i przykłady ich użycia. Aby jednak pisać czytelny kod, nadal trzeba uważać na wybór liter i słów. Oprócz wyboru poprawnych stylów nazewnictwa w kodzie, należy również starannie dobierać nazwy. Poniżej znajduje się kilka wskazówek, jak zrobić to tak skutecznie, jak to tylko możliwe.
Jak wybierać nazwy
Wybór nazw dla zmiennych, funkcji, klas i tak dalej może stanowić wyzwanie. Powinieneś poświęcić sporo uwagi na wybór nazewnictwa podczas pisania kodu, ponieważ sprawi to, że będzie on bardziej czytelny. Najlepszym sposobem na nazywanie obiektów w Pythonie jest używanie nazw opisowych, aby było jasne, co dany obiekt reprezentuje. Podczas nazywania zmiennych możesz ulec pokusie wybrania prostych, jednoliterowych nazw pisanych małymi literami, takich jak x. Ale jeśli nie używasz x jako argumentu funkcji matematycznej, nie jest jasne, co reprezentuje x. Wyobraź sobie, że przechowujesz imię osoby jako ciąg znaków i chcesz użyć cięcia ciągów znaków, aby sformatować jej imię w inny sposób. Mogłoby to wyglądać następująco:
>>> x = "John Smith"
>>> y, z = x.split()
>>> print(f"{z}, {y}")
'Smith, John'
To zadziała, ale będziesz musiał śledzić, co reprezentują x, y i z. Może to być również mylące dla współpracowników. Znacznie bardziej przejrzystym wyborem nazw byłoby coś takiego:
>>> name = "John Smith"
>>> first_name, last_name = name.split()
>>> print(f"{last_name}, {first_name}")
'Smith, John'
Podobnie, aby zmniejszyć ilość wpisywanego tekstu, kuszące może być używanie skrótów przy wyborze nazw. W poniższym przykładzie zdefiniowano funkcję db(), która przyjmuje pojedynczy argument, x, i podwaja go:
def db(x):
return x * 2
Na pierwszy rzut oka może się to wydawać rozsądnym wyborem. Nazwa db() może być skrótem od double. Ale wyobraź sobie, że wrócisz do tego kodu za kilka dni. Być może zapomniałeś, co chciałeś osiągnąć za pomocą tej funkcji, a to utrudniłoby odgadnięcie, w jaki sposób ją skróciłeś. Poniższy przykład jest znacznie bardziej przejrzysty. Jeśli wrócisz do tego kodu kilka dni po jego napisaniu, nadal będziesz w stanie odczytać i zrozumieć cel tej funkcji:
def multiply_by_two(x):
return x * 2
Ta sama filozofia dotyczy wszystkich innych typów danych i obiektów w Pythonie. Zawsze staraj się używać jak najbardziej zwięzłych, ale opisowych nazw.
Układ kodu
Sposób rozmieszczenia kodu ma ogromny wpływ na jego czytelność. W tej sekcji dowiesz się, jak dodać pionowe białe znaki, aby poprawić czytelność kodu. Dowiesz się również, jak radzić sobie z 79-znakowym limitem linii zalecanym w PEP 8.
Puste linie
Pionowe białe znaki lub puste linie mogą znacznie poprawić czytelność kodu. Zbity kod może być przytłaczający i trudny do odczytania. Podobnie, zbyt wiele pustych linii w kodzie sprawia, że wygląda on na bardzo rzadki, a czytelnik może być zmuszony do przewijania więcej niż to konieczne. Poniżej znajdują się trzy kluczowe wskazówki dotyczące stosowania pionowych białych znaków. Funkcje i klasy najwyższego poziomu należy otoczyć dwiema pustymi liniami. Funkcje i klasy najwyższego poziomu powinny być dość samodzielne i obsługiwać oddzielne funkcje. Rozsądne jest umieszczenie wokół nich dodatkowej pionowej przestrzeni, aby było jasne, że są oddzielne:
class FirstClass:
pass
class SecondClass:
pass
def top_level_function():
return None
Dlatego PEP8 sugeruje otaczanie funkcji najwyższego poziomu i definicji klas dwiema pustymi liniami. Otocz definicje metod wewnątrz klas pojedynczą pustą linią. Wszystkie metody wewnątrz klasy są ze sobą powiązane. Dobrą praktyką jest pozostawienie między nimi tylko jednej linii:
class ClassWithMethods:
def first_method(self):
return None
def second_method(self):
return None
W przykładzie kodu można zobaczyć definicję klasy z dwiema metodami instancji, które są oddzielone od siebie pojedynczą pustą linią.
Oszczędnie używaj pustych linii wewnątrz funkcji, aby pokazać wyraźne kroki. Czasami skomplikowana funkcja musi wykonać kilka kroków przed instrukcją return. Aby pomóc czytelnikowi zrozumieć logikę wewnątrz funkcji, można pozostawić pustą linię między każdym krokiem logicznym.
W poniższym przykładzie znajduje się funkcja obliczająca wariancję listy. Jest to problem dwuetapowy, więc można wskazać dwa oddzielne kroki, pozostawiając między nimi pustą linię:
def calculate_variance(numbers):
sum_numbers = 0
for number in numbers:
sum_numbers = sum_numbers + number
mean = sum_numbers / len(numbers)
sum_squares = 0
for number in numbers:
sum_squares = sum_squares + number**2
mean_squares = sum_squares / len(numbers)
return mean_squares - mean**2
W tym przykładzie kodu oddzielono kroki logiczne pustą linią między nimi, aby poprawić czytelność. Pusta linia znajduje się również przed instrukcją return. Pomaga to czytelnikowi wyraźnie zobaczyć, co zwraca funkcja. Ostrożne stosowanie pionowych białych znaków może znacznie poprawić czytelność kodu. Pomaga to czytelnikowi wizualnie zrozumieć, w jaki sposób kod jest podzielony na sekcje i jak te sekcje odnoszą się do siebie nawzajem.
Maksymalna długość linii i przerywanie linii
PEP8 sugeruje, że linie powinny być ograniczone do 79 znaków. Pozwala to na otwarcie wielu plików obok siebie, jednocześnie unikając zawijania linii. Oczywiście utrzymanie instrukcji na poziomie 79 znaków lub mniejszym nie zawsze jest możliwe. Dlatego PEP 8 opisuje również sposoby pozwalające na wykonywanie instrukcji w kilku liniach. Python zakłada kontynuację linii, jeśli kod jest zawarty w nawiasach półokrągłych lub nawiasach klamrowych, czy nawiasach kwadratowych.
def function(arg_one, arg_two,
arg_three, arg_four):
return arg_one
W tym przykładzie arg_three i arg_four zostały przeniesione do nowej linii, z wcięciem na tym samym poziomie co pierwszy argument. Możesz podzielić swój kod w ten sposób z powodu niejawnego łączenia linii wewnątrz nawiasów w Pythonie. Jeśli nie jest możliwe użycie dorozumianej kontynuacji, można zamiast tego użyć odwrotnych ukośników () do dzielenia linii:
from package import example1, \
example2, example3
Jednak za każdym razem, gdy możesz użyć dorozumianej kontynuacji, powinieneś preferować to zamiast używania odwrotnego ukośnika.
Jeśli musisz przerwać linię wokół operatorów binarnych, takich jak + i *, powinieneś to zrobić przed operatorem. Zasada ta wywodzi się z matematyki. Matematycy zgadzają się, że łamanie przed operatorami binarnymi poprawia czytelność. Porównaj dwa poniższe przykłady.
Poniżej znajduje się przykład łamania przed operatorem binarnym:
total = (first_variable
+ second_variable
- third_variable)
Możesz natychmiast zobaczyć, którą zmienną Python doda lub odejmie, ponieważ operator znajduje się tuż obok zmiennej, na której działa.
Oto przykład łamania po operatorze binarnym:
total = (first_variable +
second_variable -
third_variable)
Tutaj trudniej jest zobaczyć, którą zmienną Python dodaje, a którą odejmuje. Przerwania przed operatorami binarnymi tworzą bardziej czytelny kod, więc PEP8 zachęca do ich stosowania. Kod, który konsekwentnie przerywa się po operatorze binarnym jest nadal zgodny z PEP8. Zachęcamy jednak do łamania kodu przed operatorem binarnym.
Wcięcie
Wcięcia, czyli początkowe białe znaki, są niezwykle ważne w Pythonie. Poziom wcięcia linii kodu w Pythonie określa sposób, w jaki Python grupuje instrukcje. Rozważmy następujący przykład:
x = 3
if x > 5:
print("x is larger than 5")
Wcięte wywołanie print() informuje Pythona, że powinien wykonać tę linię tylko wtedy, gdy instrukcja if zwróci True. To samo wcięcie stosuje się, aby powiedzieć Pythonowi, jaki kod ma wykonać, gdy wywołujesz funkcję lub jaki kod należy do danej klasy.
Kluczowe zasady wcięć określone przez PEP 8 są następujące: • Używaj czterech kolejnych spacji, aby wskazać wcięcie. • Preferuj spacje zamiast tabulatorów. Podczas gdy kod Pythona będzie działał z dowolną ilością spójnych wcięć, cztery spacje są szeroko rozpowszechnioną konwencją w społeczności Pythona i powinieneś się jej trzymać.
Tabulatory a spacje
Jak wspomniano powyżej, podczas wcięć kodu należy używać spacji zamiast tabulatorów. Możesz dostosować ustawienia w edytorze tekstu, aby po naciśnięciu klawisza Tab wyświetlane były cztery spacje zamiast znaku tabulacji. Python 3 nie pozwala na mieszanie tabulatorów i spacji. Napisz poniższy kod i upewnij się, że używasz spacji w miejscach oznaczonych kropką (.) i znaku tabulacji tam, gdzie widać symbol (⇥):
def mixed_indentation(greet=True):
····if greet:
········print("Hello")
⇥ print("World") # wcięcie z tab.
mixed_indentation()
Różnica jest niewidoczna, gdy patrzysz tylko na kod, ale upewnij się, że używasz znaku tabulacji do wcięcia w linii 4, podczas gdy używasz czterech znaków spacji dla innych wcięć. Jeśli używasz Pythona 3 i uruchamiasz kod, który miesza tabulatory i spacje, otrzymasz błąd:
$ python mixed_indentation.py
File "./mixed_indentation.py", line 4
print("World") # Indented with a tab.
TabError: inconsistent use of tabs and spaces in indentation
Kod Pythona można pisać z tabulatorami lub spacjami oznaczającymi wcięcie. Jeśli jednak używasz Pythona 3, musisz być konsekwentny w swoim wyborze. W przeciwnym razie kod nie będzie działał. PEP 8 zaleca, aby zawsze używać czterech kolejnych spacji do wskazania wcięcia.
Wcięcie po złamaniu wiersza
Gdy używasz kontynuacji linii, aby utrzymać linie poniżej 79 znaków, warto użyć wcięcia, aby poprawić czytelność. Pozwala to czytelnikowi odróżnić dwie linie kodu od pojedynczej linii kodu, która obejmuje dwie linie. Istnieją dwa style wcięć, których można użyć: • Wyrównanie z separatorem otwierającym • Wcięcie wiszące
Pierwszym z nich jest wyrównanie wciętego bloku do ogranicznika otwierającego:
def function(arg_one, arg_two,
arg_three, arg_four):
return arg_one
Czasami może się okazać, że cztery spacje dokładnie pokrywają się z separatorem otwierającym. Jeśli jesteś ciekawy, w jaki sposób PEP8 sugeruje rozwiązanie tych skrajnych przypadków, możesz rozwinąć zwijaną sekcję poniżej: Kontynuacje linii, które powodują konflikty wizualne, często występują w instrukcjach if, które obejmują wiele linii, ponieważ if, spacja i nawias otwierający składają się z czterech znaków. W takim przypadku może być trudno określić, gdzie zaczyna się zagnieżdżony blok kodu wewnątrz instrukcji if:
x = 5
if (x > 3 and
x < 10):
print(x)
PEP8 nie ma ścisłego stanowiska w sprawie sposobu rozwiązania tej sytuacji, ale zapewnia dwie alternatywy, które pomagają poprawić czytelność. Jedną z możliwości jest dodanie komentarza po ostatnim warunku. Ze względu na podświetlanie składni w większości edytorów, oddzieli to warunki od zagnieżdżonego kodu:
x = 5
if (x > 3 and
x < 10):
# Oba warunki spełnione
print(x)
Komentarz wizualnie oddziela wielowierszową instrukcję if od wciętego bloku kodu. Inną opcją, o której wspomina PEP 8, jest dodanie dodatkowego wcięcia w kontynuacji linii:
x = 5
if (x > 3 and
x < 10):
print(x)
Dodając dodatkowe wcięcie w kontynuacji linii, można szybko uzyskać wizualny obraz tego, który wcięty kod jest nadal częścią instrukcji if, a który kod jest częścią wciętego bloku. Alternatywnym stylem wcięcia po podziale wiersza jest wcięcie wiszące. Jest to termin typograficzny oznaczający, że każda linia oprócz pierwszej w akapicie lub instrukcji jest wcięta. Wcięcia wiszącego można użyć do wizualnego przedstawienia kontynuacji linii kodu:
var = function(
arg_one, arg_two,
arg_three, arg_four)
Pierwszy argument, arg_one, został wcięty przy użyciu wcięcia wiszącego. Dalsze kontynuacje linii powinny być zgodne z tym samym poziomem wcięcia, co pierwsza wcięta linia.
Zauważ, że jeśli używasz wcięcia wiszącego, w pierwszej linii nie mogą znajdować się żadne argumenty. Poniższy przykład nie jest zgodny z PEP8:
var = function(arg_one, arg_two,
arg_three, arg_four)
Ten przykład nie jest zgodny z PEP8, ponieważ arg_one i arg_two zostały umieszczone w pierwszej linii obok nawiasów otwierających.
Jeśli używasz wcięcia wiszącego, powinieneś również dodać dodatkowe wcięcie, aby odróżnić kontynuowaną linię od kodu zawartego wewnątrz funkcji. Poniższy przykład jest trudny do odczytania, ponieważ kod wewnątrz funkcji znajduje się na tym samym poziomie wcięcia, co kontynuowane linie:
def function(
arg_one, arg_two,
arg_three, arg_four):
return arg_one
Zamiast tego lepiej jest użyć podwójnego wcięcia w kontynuacji linii. Pomaga to odróżnić argumenty funkcji od jej treści, poprawiając czytelność:
def function(
arg_one, arg_two,
arg_three, arg_four):
return arg_one
Podczas pisania kodu zgodnie z przewodnikiem po stylu dla kodu Pythona, 79-znakowy limit linii zmusza do dodawania podziałów linii w kodzie. Aby poprawić czytelność, należy wciąć kontynuowaną linię, aby pokazać, że jest to kontynuowana linia.
Jak pokazano powyżej, można to zrobić na dwa sposoby:
1. Wyrównaj wcięty blok z ogranicznikiem otwierającym.
2. Użyj wcięcia wiszącego.
Możesz wybrać jedno z tych dwóch podejść do wcięcia kodu po podziale wiersza. Gdzie umieścić nawias zamykający Kontynuacje linii pozwalają przerywać linie wewnątrz nawiasów, nawiasów klamrowych lub nawiasów klamrowych. Nawias zamykający może nie być głównym celem podczas programowania, ale nadal ważne jest, aby umieścić go w rozsądnym miejscu. W przeciwnym razie może zmylić czytelnika.
PEP8 zapewnia dwie opcje położenia nawiasu zamykającego w implikowanych kontynuacjach linii: • Ustaw nawias zamykający w jednej linii z pierwszym znakiem poprzedniej linii niebędącym spacją:
list_of_numbers = [
1, 2, 3,
4, 5, 6,
7, 8, 9
]
• Ustaw nawias zamykający w jednej linii z pierwszym znakiem linii rozpoczynającej konstrukcję:
list_of_numbers = [
1, 2, 3,
4, 5, 6,
7, 8, 9
]
Możesz wybrać dowolną opcję. Jednak, jak zawsze, kluczowa jest konsekwencja, więc staraj się trzymać jednej z powyższych metod.
Mam nadzieję, że przedstawione tu zasady pozwolą Ci pisać piękny kod w Pythonie, a każdy kto go będzie czytał podziękuje Ci za stosowanie tych zasad.