Jak vám Zen of Python může pomoci napsat lepší kód

Photo of author

By etechblogcz

Chcete se zdokonalit v programování v jazyce Python? Tento průvodce vám ukáže, jak vám „Zen Pythonu“ pomůže udělat první kroky na této cestě.

Python je obecně považován za snadný jazyk pro učení. Nicméně, psaní kódu, který je „Pythonic“ – tedy idiomatický a snadno udržovatelný – může být náročné, zvláště pro začínající programátory. „Zen Pythonu“, báseň od Tima Peterse (známá také jako PEP-20), zdůrazňuje důležitost psaní kódu v Pythonu, který je v souladu s osvědčenými postupy.

Chcete-li si přečíst „Zen Pythonu“, spusťte Python REPL a zadejte:

>>> 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 vidíte, většina aforismů v „Zenu Pythonu“ je srozumitelná. Některé aforismy by měly být interpretovány ve spojení s ostatními, zatímco jiné mohou zdánlivě odporovat předchozím myšlenkám. Nicméně, „Zen Pythonu“ je inspirativní, podnětný a praktický text!

Výklad „Zenu Pythonu“

„Zen Pythonu“ byl navržen tak, aby poskytoval 20 základních principů pro programování v Pythonu. Nicméně, existuje pouze 19 aforismů. Projděme si je.

Krásné je lepší než ošklivé

Tento aforismus zdůrazňuje, že bychom měli psát kód, který je elegantní a „Pythonic“.

Následující kódový fragment „zapáchá“ kódem:

def square(num):
    squares = []
    for i in range(num):
        squares.append(i*i)
    return squares

Tato funkce:

  • Inicializuje prázdný seznam
  • Obsahuje smyčku, která postupně přidává prvky na konec seznamu
  • A nakonec vrací tento seznam

Ačkoli je funkčně správná, není „Pythonic“ a je náročná na údržbu.

Můžete ji napsat mnohem elegantněji s využitím generátorů. Zde je funkce generátoru, která je ekvivalentní výše uvedené:

def square(num):
    for i in range(num):
        yield i*i

Nebo ještě lépe, můžete použít tzv. „generator expression“:

num = ...
squares = (i*i for i in range(num))

Explicitní je lepší než implicitní

Při psaní kódu byste neměli ostatní vývojáře ani uživatele nutit odhadovat chování kódu. Buďte explicitní. Zvažte například použití importu se zástupnými znaky:

from some_module import * # import se zástupným znakem
from some_other_module import *

result = some_function() # odkud se vzala tato funkce?

Vyhýbejte se importům se zástupnými znaky. Jsou nejednoznačné a neefektivní. Při importu funkcí a tříd z jiných modulů buďte konkrétní:

from some_module import this_function # explicitní import

result = this_function() # nyní víme, odkud se vzala

Jednoduché je lepší než složité

Tento aforismus nás vybízí k tomu, abychom udržovali kód jednoduchý a vyhýbali se zbytečné složitosti. Například, chcete-li obrátit řetězec, můžete implementovat následující rekurzivní řešení:

def reverse_string(my_string):
  if my_string == "":
    return my_string
  else:
    return reverse_string(my_string[1:]) + my_string[:1]

Ačkoli toto řešení funguje, je zbytečně složité, protože existují jednodušší a „Pythonic“ způsoby, jak to udělat.

Zde je řešení s využitím tzv. „slicing“:

>>> rev_string = my_string[::-1]
>>> rev_string
'nohtyP'

A zde je přístup s využitím vestavěných metod a funkcí:

>>> rev_string = ''.join(reversed(my_string))
>>> rev_string
'nohtyP'

Složité je lepší než komplikované

Co nám tedy říká tento další aforismus z „Zenu Pythonu“?

Obrácení řetězce v Pythonu je jednoduchá operace. Nicméně, v praxi můžeme potřebovat složitější logiku. Zde je poměrně jednoduchý příklad:

Představte si, že se potřebujete připojit k databázi:

  • Nejprve musíte analyzovat konfigurační soubor (např. TOML) pro získání konfiguračních informací o databázi.
  • Musíte mít nainstalovaný konektor databáze.
  • Poté můžete definovat funkci pro připojení k databázi, včetně ošetření chyb připojení, a dalších souvisejících úkonů.
  • Nakonec, po úspěšném připojení, můžete databázi dotazovat.

Ačkoli je tento proces poměrně jednoduchý, vyžaduje složitější logiku než pouhé obrácení řetězce. Ale to neznamená, že by musel být komplikovaný. Stále můžete efektivně používat funkce z vestavěných modulů a organizovat svůj kód tak, aby ho ostatní vývojáři mohli číst, chápat a přispívat k němu.

Ploché je lepší než vnořené

Plochá struktura je snáze analyzovatelná a pochopitelná než vnořená. Při práci na projektu můžete být v pokušení izolovat funkčnost vytvářením samostatných modulů. Nicméně, příliš velká granularita může být kontraproduktivní.

To neznamená, že se vždy musíte vyhýbat vnořené struktuře. Pokud však vnoření potřebujete, omezte ho na minimum.

Zde je příklad:

from db_info.config.actions.parse.parse_config import parse_toml # příliš složité pro analýzu!
...

from db_config.parse_config import parse_toml # mnohem lepší!

Řídké je lepší než husté

Pokud teprve začínáte svou cestu vývojáře, můžete mít tendenci nadužívat některé funkce jazyka. Například, „list comprehensions“ jsou v Pythonu považovány za „Pythonic“, ale pouze tehdy, pokud se používají tam, kde jsou vhodné.

Podívejte se na následující „list comprehension“:

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)
# Output: [('melons', 40)]

Tato „list comprehension“ je příliš hustá a náročná na analýzu. V tomto případě by bylo použití ekvivalentní smyčky `for` s podmínkami čitelnější. Význam tohoto „list comprehension“ je obtížné pochopit.

Čitelnost se počítá

Vždy byste měli psát čitelný kód. Zde je několik jednoduchých způsobů, jak toho dosáhnout:

  • Používejte popisné názvy proměnných.
  • Přidávejte „docstring“ pro funkce a třídy.
  • Komentujte kód tam, kde je to potřeba.
  • Přidávejte „type hints“ pro argumenty a návratové typy funkcí.

Speciální případy nejsou natolik zvláštní, aby porušovaly pravidla

Měli byste se co nejvíce držet pravidel jazyka a doporučených osvědčených postupů.

Je to však vždy možné? Ne, a proto zde máme další aforismus.

I když praktičnost poráží čistotu

Toto je pokračování předchozího aforismu. Ačkoli se doporučuje dodržovat pravidla jazyka, v určitých situacích je naprosto v pořádku některé zásady opomenout.

Chyby by nikdy neměly projít tiše

V Pythonu jsou chyby za běhu poměrně běžné. Je dobrým zvykem, že byste se měli vždy snažit chyby ošetřit, a ne je ignorovat.

Můžete předvídat a implementovat vhodné ošetření chyb pro různé typy chyb:

try:
    # kód, který může vyvolat chybu
except ErrorType1:
    # ošetření chyby ErrorType1
except ErrorType2:
    # ošetření chyby ErrorType2
...

Měli byste se vyhýbat obecným výjimkám bez specifikace typu chyby. Novější verze Pythonu (od Pythonu 3.11) podporují zřetězení výjimek a skupiny výjimek, aby bylo možné provádět sofistikovanější ošetření výjimek.

Pokud není výslovně umlčena

Tento aforismus navazuje na předchozí. Pokud návrh vyžaduje nebo umožňuje umlčení chyby, mělo by to být provedeno explicitně.

Například: při připojování k databázi můžete narazit na `OperationalError` z důvodu neplatných konfiguračních informací. Můžete se pokusit o připojení s využitím vlastního nastavení. V případě, že dojde k chybě `OperationalError`, použijte výchozí konfiguraci a zkuste se připojit k databázi.

try:
   # připojení s využitím vlastního nastavení
except OperationalError:
   # připojení s využitím výchozího nastavení

Tváří v tvář nejasnostem odmítněte pokušení hádat

Tento aforismus v „Zenu Pythonu“ je srozumitelný. Pokud si nejste jisti, nehádejte. Spusťte kód a ověřte výstup. Poté, v závislosti na tom, zda máte požadované chování, vylepšete čitelnost nebo upravte logiku kódu.

Zvažte následující jednoduchý příklad s n-ticí booleanů:

>>> True, True == (True, True)
(True, False)
>>> True, (True == (True, True))
(True, False)
>>> (True, True) == (True, True)
True

Měl by existovat jeden – a nejlépe pouze jeden – zřejmý způsob, jak to udělat

Pro splnění určitého úkolu by měl existovat pouze jeden doporučený, „Pythonic“ způsob, jak to provést. Pro jakýkoli problém však můžeme mít několik řešení.

Dokonce i v jednoduchém příkladu s obrácením řetězce jsme viděli rekurzivní řešení, „slicing“ a metodu `join()`.

Jedná se také o interní vtip vzhledem k nekonzistentnímu používání pomlček „em dash“. Obvykle používáme „em dash“ bez úvodních a koncových mezer. Nebo ji používáme s úvodní i koncovou mezerou.

Takže zde je, co můžeme odvodit. Aforismus, který zdůrazňuje, že by měl existovat jeden – a pouze jeden – „Pythonic“ způsob, jak dělat věci, může být napsán více než dvěma způsoby.

I když to nemusí být zpočátku zřejmé, pokud nejste Holanďané

Tento aforismus odkazuje na Guida Van Rossuma, tvůrce Pythonu (který je Holanďan). Nejpřirozenější způsob, jak dosáhnout určitého úkolu, je přirozený právě pro tvůrce Pythonu.

Pro vývojáře to vyžaduje zkušenosti a učení se ze zkušeností, aby se naučili lépe využívat funkce jazyka.

Teď je to lepší než nikdy

Stejně jako u několika dalších aforismů v „Zenu Pythonu“, i tento lze interpretovat několika různými způsoby.

Jedna z interpretací je, že je běžné otálet se zahájením kódování projektu. Spíše než čekat na naplánování všech jemných detailů projektu, je lepší nápad začít hned.

Další možná interpretace je: kód, který běží v konečném počtu kroků a končí, je často lepší než kód, který je „zabugovaný“ a uvízne v nekonečné smyčce.

I když nikdy není často lepší než právě teď

Zdá se, že tento aforismus je v rozporu s předchozím. Ačkoli je lepší neotálet, měli bychom problém nejprve promyslet a na základě toho navrhnout kód.

Kódování bez náležitého zamyšlení, s „code smellem“ a anti-vzory, je špatný nápad. Takový kód je obtížné refaktorovat a implementovat nápravná opatření.

Pokud se implementace těžko vysvětluje, je to špatný nápad

Jakákoli logika, jakkoli může být složitá, může být vždy implementována tak, aby byla srozumitelná a snadno pochopitelná.

Pokud je implementace obtížná na vysvětlení, pravděpodobně je zbytečně složitá. Kód lze upravit nebo přepracovat tak, aby byl snáze sledovatelný.

Pokud je implementace snadno vysvětlitelná, může to být dobrý nápad

Tento aforismus souvisí s předchozím a je také srozumitelný sám o sobě. Pokud lze implementaci vysvětlit jednoduše, pak je to pravděpodobně dobrý nápad.

Kód, jehož implementaci lze popsat jednoduše, bude pravděpodobně čitelný, snadno sledovatelný, a s minimální složitostí.

Jmenné prostory jsou skvělý nápad – pojďme jich dělat víc!

V Pythonu lze k objektům v určitém rozsahu přistupovat pomocí jejich jmen v jejich jmenném prostoru. Můžete například vytvořit třídu a použít ji jako šablonu k vytvoření instancí této třídy. Všechny proměnné instance budou uloženy v jmenném prostoru dané instance.

To nám umožňuje používat objekty se stejným názvem, aniž by docházelo ke konfliktům, pokud se nacházejí v různých jmenných prostorech. Měli byste je však používat uvážlivě a zajistit, aby nebyla ohrožena jednoduchost a čitelnost kódu.

Závěr

To je vše pro tento tutoriál! Doufám, že vám tento průvodce pomohl pochopit, jak „Zen Pythonu“ zdůrazňuje styl kódu a správné postupy v Pythonu. Čím více kódujete, tím lépe se v tom budete zlepšovat.

Pokud se chcete naučit psát stručný a čitelný kód, přečtěte si tento článek o „one-liners“ v Pythonu.