Pisz lepszy kod w Pythonie
Czy nie lepiej byłoby zająć się strukturą i czytelnością kodu od razu? Oto kilka prostych kroków, które pozwolą Ci wyczyścić kod w Pythonie. Wypróbuj te metody na jednym ze swoich skryptów, a zobaczysz jak to przekłada się na czytelność, łatwość utrzymania i testowalność. Następnym razem, gdy otrzymasz nowe zadanie, spróbuj wdrażać te taktyki na bieżąco. Sprawi to, że kodowanie będzie o wiele bardziej przyjemne.
Skonfiguruj edytor tekstu, aby formatował Twój kod w PEP8
Pierwszym krokiem do wyczyszczenia kodu w Pythonie jest formatowanie kodu zgodnie z PEP8. Chociaż warto przeczytać specyfikację PEP8, z pewnością nie będziesz formatować każdej linijki osobno. To może potrwać wieczność. Na szczęście istnieją narzędzia, które pomogą z formatowaniem.
Popularne pakiety Pythona do automatycznego formatowania zgodnego z PEP8 to autopep8, black oraz yapf. Możesz je skonfigurować tak, żeby automatycznie formatowały kod przy zapisie. Oto lista popularnych edytorów tekstu z linkami do konfiguracji automatycznego formatowania.
- PyCharm(używając Black, ale możesz to zrobić dla dowolnego narzędzia do formatowania kodu)
- VS Code
- Spyder
- Atom
- Jupyter Notebooks
- Sublime Text
Używam PyCharm, który domyślnie używa PEP8 oraz podświetla niezgodności z tymi wytycznymi w edytorze wraz z podpowiedziami, jak je naprawić. Możesz także uruchomić narzędzie Code > Reformat Code, które po prostu wykonuje formatowanie.
W PyCharm można użyć funkcji File Watcher, aby automatycznie uruchomić formatowanie przy okazji zapisywania plików. Jeśli używasz terminala i edytora tekstu, takiego jak vim, możesz po prostu uruchomić dowolny z powyższych pakietów Pythona w wierszu poleceń i podać ścieżkę do kodu, który wymaga formatowania.
Używaj f-strings do formatowania ciągów znaków
Python 3.6 wprowadził wiele nowych i ekscytujących funkcji, ale f-strings jest moją ulubioną. F-strings zapewniają czysty oraz czytelny sposób formatowania ciągów, umożliwiając wstawianie zmiennych wewnątrz ciągu znaków w nawiasach klamrowych.
Oto przykład starego sposobu formatowania ciągów znaków za pomocą %
. Podczas korzystania z tej metody, gdy liczba zmiennych rośnie, kod staje się mniej czytelny.
>>> first = "Sam"
>>> last = "Miller"
>>> middle "Douglas"
>>> "You are a fantastic programmer, %s %s %s." % (first, middle, last)
'You are a fantastic programmer, Sam Douglas Miller.'
Kiedyś można było użyć metody str.format()
klasy String. str.format()
daje te same rezultaty, ale powoduje też te same problemy z czytelnością.
>>> "You are a fantastic programmer, {} {} {}.".format(first, middle, last)
'You are a fantastic programmer, Sam Douglas Miller.'
A teraz użyj f-strings:
>>> f"You are a fantastic programmer, {first} {middle} {last}"
You are a fantastic programmer, Sam Douglas Miller.
Umieść „f” przed ciągiem, a Python rozpozna wszelkie terminy w nawiasach klamrowych jako zmienne. Upewnij się, że zmienne są zdefiniowane, zanim utworzysz f-string, bo inaczej Python rzuci błąd. Używanie f-strings może sprawić, że Twój kod będzie znacznie bardziej czytelny.
Twoje funkcje powinny robić tylko jedną rzecz
Wszyscy widzieliśmy funkcje, które mają setki linijek kodu. Programiści, którzy piszą taki kod (sama tak kiedyś robiłam), starają się uczynić swój kod bardziej czytelnym poprzez dodawanie komentarzy do każdej sekcji, a refaktoryzację odkładają na później. Mogli od razu uczynić swój kod łatwiejszym do zarządzania, tworząc funkcję lub metodę klasy dla każdego zadania.
Podziel kod na poszczególne działania i napisz osobną funkcję dla każdego z nich. Spraw, aby nazwa każdej funkcji była czytelnym słowem (o tym w następnej części). W ten sposób Ty i inni programiści możecie czytać swój kod jak książkę.
Nie wspominając już o tym, że dzięki większej liczbie funkcji możesz używać IDE do nawigacji po funkcjach, aby elegancko poruszać się w kodzie. Tworzenie funkcji, które wykonują jedną rzecz, sprawia, że kod jest bardziej testowalny. Spróbuj napisać test jednostkowy dla swojej funkcji, która ma 400 linii, a obiecuję, że skończysz na rozbijaniu kodu na wiele funkcji. Nie martw się o koszty związane z tworzeniem kolejnych funkcji; nie jest to istotne.
Zamień to:
def print_page(banner_text, banner_images, content, footer_text):
# Print banner
print("")
print("Title:")
print(banner_text)
print("")
# Do some image processing
for images in banner_images:
compress(banner_images)
height, width = banner_images["size"]
new_image = size(height, width)
# Print banner image
render(new_image)
# Print content
print("")
print("")
print(content)
# Print footer
footer_length = len(footer_text)
for i in range(0, footer_length):
print("---------")
print(footer_text)
and so on.....
Na to:
def print_page(banner_text, banner_images, content, footer_text):
print_banner(banner_text)
render_images(banner_images)
print_content(content)
print_footer(footer_text)
Większość współczesnych edytorów tekstu ma funkcję Refactor> Extract> Method, która pozwala na wyłączenie fragmentów kodu do nowej funkcji lub metody.
Przestań skracać nazwy zmiennych
Zasada ta tyczy się każdego języka programowania. Pomimo tego, że dany skrót będzie oczywisty dla Ciebie, nie zawsze będzie on oczywisty dla kogoś innego. Nie musisz oszczędzać miejsca na ekranie, więc zapisuj nazwy zmiennych i klas pełnymi słowami i wyrażeniami.
Zamień to:
cdte = datetime.date.today()
Na to:
current_date = datetime.date.today()
Zamień to:
class maapic:
...
Na to:
class MyAwesomeApiClient:
...
Zamień to(?):
my_d_anal = (x + y + z) * t
Na to:
my_data_analysis = (some + meaningful + names) * time
Przeczytaj to, co właśnie piszesz i zastąp skrócone nazwy całymi słowami. Wszyscy będą Ci za to wdzięczni, łącznie z Twoim przyszłym ja.
Używaj wyrażeń listowych (ang. list comprehensions)
W większości języków programowania, gdy musimy uruchomić jakiś kod dla każdego elementu na liście, używamy pętli for. Jeżeli język to obsługuje, to korzystamy z funkcji typu map, reduce czy filter. Wyrażenia listowe to świetne narzędzie, jeśli trzeba zastosować jakiś fragment kodu do każdego elementu na liście (tak jak w przypadku funkcji map).
Zamień to:
new_list = []
for item in items:
new_list.extend(item * 2)
Na to:
new_list = [item * 2 for item in items]
Aby to lepiej zobaczyć, zacznij od końca. Wyrażenie for item in items
to pętla w tej linijce kodu. Cofając się, item * 2
jest stosowany dla każdej pozycji na liście. Na koniec []
mówi Pythonowi, aby zwrócił listę z obliczonymi elementami. Jeśli masz bardziej skomplikowane instrukcje dla każdego elementu na liście, możesz wtedy stworzyć funkcję.
def process(item):
item = item * 2
item = item / 5
item = item + 12
return item
# Done with the map function
new_list = map(process, items)
# With a list comprehension, better readability!
new_list = [process(item) for item in items]
Możesz także filtrować listę elementów poprzez użycie wyrażenia listowego. Na końcu dodajemy klauzulę if
, która mówi, aby wybierać element z listy tylko, jeśli jest on większy niż 5.
filtered = [item for item in items if item > 5]
Możesz także połączyć te dwie techniki. Uważaj jednak. Jeśli dodasz zbyt wiele klauzul do swoich wyrażeń listowych, może się to szybko zrobić nieczytelne. Jeśli tak się stanie, utwórz helper.
final_list = [process(item) for item in items if item > 5]
Stwórz funkcje pomocnicze
Zasadę tę można również nazwać „Nie bądź taki mądry”. Kiedy wyrażenia listowe lub dowolny fragment kodu staje się zbyt skomplikowany i nieczytelny (nawet dla Ciebie) to raczej nie ma sensu, żeby ktoś inny rozczytywał Twój kod. W takich przypadkach dobrze jest stworzyć funkcję pomocniczą lub metodę klasy o czytelnej nazwie.
Zamień to:
final_items = [process(item) for subitems in items
for subitems2 in subitems
for item in subitems2
if item == "correct"]
Na to (w tym przypadku, użycie pętli ma sens, jeśli wyrażenie listowe jest zbyt skomplikowane):
def select_correct_items(items):
correct = []
for subitems in items:
for subitems2 in subitems:
correct = [item in subitems2 if item == "correct"]
return correct
# this is readable
final_items = select_correct_items(items)
Staraj się tworzyć funkcje pomocnicze dla często używanych i skomplikowanych zadań.
Dodawaj docstrings
Gdy wszystko inne zawiedzie, a Twój kod może być już zbyt skomplikowany, upewnij się, że Twoje docstrings są aktualne. Dobrze sformatowany docstring Pythona dla funkcji wyglądałby tak:
def some_func(myParam1, myParam2):
"""
This is where you add what your function does
@param myParam1: (int) An integer for input
@param myParam2: (int) An integer for input
@return: (str) A string meesage
"""
Docstring pozwala użytkownikom Twojego kodu korzystać ze wbudowanego narzędzia pomocy Python, aby odkryć dokumentację twoich funkcji.
W PyCharm możesz łatwo dodawać docstring do wszystkich modułów, klas, funkcji i metod klas, wpisując trzy cudzysłowy i naciskając Enter. Ten prosty krok automatycznie tworzy szablon docstring do wypełnienia w Pycharm. Inne edytory tekstu mają wtyczki do dodawania docstring na podstawie sygnatury metody czy funkcji.