Jak používat kontrolu statického typu v Pythonu 3.6

Automaticky zachycuje mnoho běžných chyb při kódování

Jednou z nejčastějších stížností na jazyk Python je to, že proměnné jsou dynamicky napsané. To znamená, že deklarujete proměnné, aniž byste jim dali konkrétní datový typ. Typy jsou automaticky přiřazovány na základě toho, v jakých datech byla předána:

V tomto případě je proměnná president_name vytvořena jako typ str, protože jsme předali řetězec. Ale Python nevěděl, že by to byl řetězec, dokud by tento řádek kódu skutečně nespustil.

Pro srovnání, jazyk jako Java je Statically Typed. Chcete-li v jazyce Java vytvořit stejnou proměnnou, musíte řetězec explicitně deklarovat pomocí typu String:

Protože Java ví předem, že president_name může držet pouze řetězec, dá vám chybu při kompilaci, pokud se pokusíte udělat něco hloupého, jako byste do něj uložili celé číslo nebo jej předáte do funkce, která očekává něco jiného než řetězec.

Proč bych se měl starat o typy?

Je obvykle rychlejší psát nový kód v dynamicky psaném jazyce, jako je Python, protože nemusíte psát všechna typová prohlášení ručně. Když se však vaše kódová základna začne zvětšovat, nevyhnutelně narazíte na spoustu běhových chyb, které by statickému psaní zabránilo.

Zde je příklad neuvěřitelně běžné chyby v Pythonu:

Vše, co děláme, je požádat uživatele o jeho jméno a poté vytisknout „Ahoj, !“. A pokud uživatel nic nenapíše, chceme vytisknout „Ahoj, UserFirstName!“ Jako záložku.

Tento program bude fungovat perfektně, pokud jej spustíte a zadáte jméno ... Ale pokud necháte jméno prázdné, ztratí se:

Traceback (poslední poslední hovor):
  Soubor "test.py", řádek 14, v 
    first_name = get_first_name (fall__name)
  Soubor "test.py", řádek 2, v get_first_name
    return full_name.split ("") [0]
AttributeError: 'dict' objekt nemá atribut 'split'

Problém je v tom, že jméno fallback_name není řetězec - je to slovník. Takže volání get_first_name na fallback_name hrozně selže, protože nemá funkci .split ().

Je to jednoduchá a zjevná chyba, kterou lze opravit, ale tato chyba je zákeřná v tom, že nikdy nebudete vědět, že chyba existuje, dokud uživatel náhodou nespustí program a nezmění jméno. Můžete si program otestovat tisíckrát sami a nikdy si nevšimnete této jednoduché chyby, protože jste vždy zadali jméno.

Statické psaní zabraňuje tomuto druhu chyb. Než se dokonce pokusíte spustit program, statické psaní vám řekne, že nemůžete předat fallback_name do get_first_name (), protože očekává str, ale dáte mu diktát. Editor kódu může chybu zvýraznit i při psaní!

Když se tento druh chyby objeví v Pythonu, obvykle to není v takové jednoduché funkci. Chyba je obvykle v kódu uložena o několik vrstev dolů a spuštěna, protože předaná data se mírně liší, než se původně očekávalo. Chcete-li jej odladit, musíte znovu vytvořit vstup uživatele a zjistit, kde se to pokazilo. Tolik času je zbytečné ladit tyto snadno odstranitelné chyby.

Dobrou zprávou je, že nyní můžete v Pythonu používat statické psaní. A od Pythonu 3.6 je konečně rozumná syntaxe pro deklarování typů.

Oprava našeho buggy programu

Aktualizujme program buggy deklarováním typu každé proměnné a každé funkce vstupu / výstupu. Zde je aktualizovaná verze:

V Pythonu 3.6 deklarujete typ proměnné takto:

název proměnné: typ

Pokud při vytváření proměnné přiřadíte počáteční hodnotu, je to tak jednoduché jako toto:

my_string: str = "Moje hodnota řetězce"

A vy deklarujete typy vstupů a výstupů funkce takto:

def function_name (parametr1: type) -> return_type:

Je to docela jednoduché - jen malé vylepšení oproti normální syntaxi Pythonu. Ale teď, když jsou typy deklarovány, podívejte se, co se stane, když spustím kontrolu typu:

$ mypy typing_test.py
test.py:16: chyba: Argument 1 k "get_first_name" má nekompatibilní typ Dict [str, str]; očekávaný "str"

Bez provedení programu ví, že neexistuje žádný způsob, jak by linka 16 fungovala! Chybu můžete opravit hned teď, aniž byste čekali, až ji uživatel odhalí za tři měsíce.

A pokud používáte IDE, jako je PyCharm, automaticky zkontroluje typy a ukáže, kde je něco špatně, ještě než stisknete „Spustit“:

Je to tak snadné!

Další příklady syntaxe psaní Pythonu 3.6

Deklarování proměnných str nebo int je jednoduché. Bolesti hlavy se vyskytují, když pracujete se složitějšími datovými typy, jako jsou vnořené seznamy a slovníky. Naštěstí nová syntaxe Pythonu 3.6 není příliš špatná - alespoň ne pro jazyk, který přidal psaní jako dodatečnou myšlenku.

Základním vzorem je importovat název komplexního datového typu z modulu pro psaní a poté předat vnořené typy v závorkách.

Nejběžnější typy dat, které budete používat, jsou Dict, List a Tuple. Vypadá to, jak je používat:

zadáním importu Dict, List
# Slovník, ve kterém jsou klíče řetězce a hodnoty jsou ints

name_counts: Dict [str, int] = {
    "Adam": 10,
    "Guido": 12
}
# Seznam celých čísel

čísla: Seznam [int] = [1, 2, 3, 4, 5, 6]
# Seznam, který obsahuje příkazy, které obsahují řetězec / int hodnotu

list_of_dicts: List [Dict [str, int]] = [
    {"key1": 1},
    {"key2": 2}
]

Tuples jsou trochu zvláštní, protože umožňují deklarovat typ každého prvku zvlášť:

z psaní importu Tuple

my_data: Tuple [str, int, float] = ("Adam", 10, 5,7)

Také můžete vytvářet aliasy pro složité typy jejich přiřazením k novému jménu:

od psaní seznamu importu, Tuple

LatLngVector = Seznam [Tuple [float, float]]

body: LatLngVector = [
    (25,91375, -60,15503),
    (-11,01983, -166,48477),
    (-11,01983, -166,48477)
]

Někdy mohou být vaše funkce Pythonu dostatečně flexibilní, aby zvládly několik různých typů nebo pracovaly na jakémkoli datovém typu. Typ Unie můžete použít k deklaraci funkce, která může přijímat více typů, a můžete použít Kdokoli k přijetí všeho.

Python 3.6 také podporuje některé z fantastických textů, které jste mohli vidět v jiných programovacích jazycích, jako jsou generické typy a uživatelské uživatelem definované typy.

Spuštění nástroje Kontrola typu

Zatímco Python 3.6 vám dává tuto syntaxi pro deklarování typů, v Pythonu neexistuje nic, co by s těmito deklaracemi něco dělalo. Chcete-li skutečně vynutit kontrolu typu, musíte udělat jednu ze dvou věcí:

  1. Stáhněte si open-source mypy type checker a spusťte jej jako součást vašich testů jednotek nebo pracovního postupu vývoje.
  2. Použijte PyCharm, který má vestavěnou kontrolu typu v IDE. Nebo pokud používáte jiný editor, jako je například Atom, stáhněte si vlastní plugin pro kontrolu typu.

Doporučil bych dělat obojí. PyCharm a mypy používají implementace různých typů kontrol a každý může zachytit věci, které ostatní ne. Můžete použít PyCharm pro kontrolu typu v reálném čase a pak spustit mypy jako součást vašich jednotkových testů jako závěrečné ověření.

Skvělý! Měl bych začít psát celý svůj Pythonův kód deklarací typu?

Syntaxe deklarace typu je pro Python velmi nová - funguje pouze od Pythonu 3.6. Pokud ukážete zadaný kód Python jinému vývojáři Pythonu, existuje velká šance, že si budou myslet, že jste blázni, a ani nevěří, že je syntaxe platná. A kontrola typu mypy je stále ve vývoji a dosud netvrdí, že je stabilní.

Takže to může být trochu brzo jít na to celé prase pro všechny vaše projekty. Pokud ale pracujete na novém projektu, kde můžete nastavit Python 3.6 jako minimální požadavek, může být vhodné experimentovat s psaní. Má potenciál zabránit spoustě chyb.

Jednou z úhledných věcí je, že můžete snadno kombinovat kód s deklaracemi typu out a out. Není to všechno - nebo nic. Takže můžete začít tím, že deklarujete typy na místech, která jsou nejcennější, aniž byste změnili celý kód. A protože Python sám s těmito typy za běhu nic nedělá, nemůžete náhodou program přerušit přidáním deklarací typu.

Děkuji za přečtení! Máte-li zájem o strojové učení (nebo jen chcete pochopit, co to je), podívejte se na moje Strojové učení je zábava! série.

Můžete mě také sledovat na Twitteru na @ageitgey nebo najít na linkin.