Evoluce Pythonu

Moderní techniky, nová syntaxe a trendy

Pavel Tišnovský

Vydavatel:

CZ.NIC, z. s. p. o.

Milešovská 5, 130 00 Praha 3

Edice CZ.NIC

www.nic.cz

1. vydání, Praha 2024

Kniha vyšla jako 31. publikace v Edici CZ.NIC.

ISBN 978-80-88168-76-8

© 2024 Pavel Tišnovský

Toto autorské dílo podléhá licenci Creative Commons BY-ND 4.0 (https://creativecommons.org/licenses/by-nd/4.0/). Dílo však může být překládáno a následně šířeno v písemné či elektronické formě, na území kteréhokoliv státu, za předpokladu, že nedojde ke změně díla a i nadále zůstane zachováno označení autora a prvního vydavatele díla, sdružení CZ.NIC, z. s. p. o. Překlad může být šířen pod licencí CC BY-ND 4.0.

ISBN 978-80-88168-76-8

— Pavel Tišnovský

Evoluce Pythonu

Moderní techniky, nová syntaxe a trendy

— Edice CZ.NIC

Předmluva vydavatele

Předmluva vydavatele

Python je programovací jazyk s dlouhou historií a širokým využitím od jednoduchých skriptů až po webové služby. V průběhu své existence se (stejně jako další jazyky) dále vyvíjí a mění, a je tedy třeba sledovat nové možnosti a trendy. Tato kniha nás provede historií jazyka a ukáže nejdůležitější novinky a změny, které nastaly za posledních 9 let. Jednotlivé nové vlastnosti jsou vždy popsány a doprovázeny příklady. Pochopení jejich dosahu a možného využití je tedy velmi jednoduché. Poměrně velká část knihy je věnována funkcionálnímu programování a jeho použití v Pythonu, a to jak v rámci standardní knihovny, tak i knihovny funcy. Popisuje přístupy a nástroje, které jsou potřeba k použití Pythonu jako funkcionálního jazyka. Zmíněna je též podpora pro běh aplikací ve více vláknech a/nebo procesech. Jsou probrány jednotlivé přístupy k paralelnímu zpracování včetně ukázek a benchmarků. Také je zde popsána možnost řízení a komunikace uvnitř tohoto typu aplikací. Za perličku považuji zmínění použití Pythonu pro vývoj frontendu webových aplikací, a to buď pomocí překladu Python kódu do JavaScriptu/WebAssembly, nebo použitím Python interpretru přímo ve webovém prohlížeči. Poslední část knihy je věnována správci projektů PDM a linteru Ruff. Nástroje tohoto typu jsou nedílnou součástí ekosystému a také zde dochází k vývoji a posunům standardů. Tyto relativně nové nástroje jsou představeny jako zajímavé alternativy k těm v současnosti rozšířeným. Kniha bude zajímavým doplněním knihovničky každého programátora (nejen) v Pythonu, své uplatnění ale nalezne určitě i u ostatních.

So, happy Pythoning and... always look on the bright side of life...

Tomáš Pazderka, CZ.NIC

Praha, 26. února 2024

Obsah

Obsah

Předmluva vydavatele

1 Úvod

2 Stručná historie vývoje Pythonu

2.1 Předchůdce Pythonu: programovací jazyk ABC

2.2 Slibný začátek, ale pouze začátek

2.3 Odsazování řádků zdrojového kódu v jazycích ABC a Python

2.4 Dvojtečka zapisovaná na začátku bloků kódu

2.5 Další skriptovací jazyk na již obsazené nice?

2.6 Od Pythonu 0.9.0 k Pythonu 3.12

2.7 Popularita Pythonu

3 Rozsáhlý svět programovacího jazyka Python v současnosti

3.1 Standardní interpretr Pythonu: de facto standard jazyka

3.2 Varianty Pythonu určené pro běh ve virtuálních strojích

3.3 Překladače Pythonu

3.4 Python ve webových prohlížečích

3.5 MicroPython

4 Postupné rozšiřování syntaxe a sémantiky Pythonu

4.1 Formátovací řetězce

4.2 Klíčová slova async a await

4.3 Specifikace pozičních parametrů funkcí

4.4 Mroží operátor

4.5 Generické datové typy

4.6 Pattern matching

4.7 Skupiny výjimek

4.8 Klíčové slovo type

4.9 Nová syntaxe pro zápis generických typů

4.10 Maticové násobení

4.11 Operace rozbalení

5 Typové anotace

5.1 Vliv zavedení typových anotací na další vývoj Pythonu

5.2 Statické a dynamické typové systémy

5.3 Postupný přechod od jazyků s dynamickým typovým systémem k jazykům s volitelnými typy

5.4 Nástroj Mypy

5.5 Typové anotace a systém datových typů Pythonu

5.6 Variance

6 Funkcionální paradigma

6.1 Čistě funkcionální jazyky vs. hybridní jazyky

6.2 Funkce vyššího řádu akceptující jinou funkci jako svůj parametr

6.3 Funkce vyššího řádu vracející jinou funkci

6.4 Implementace většiny standardních operátorů Pythonu formou funkcí

6.5 Standardní funkce vyššího řádu: map, filter a reduce/fold

6.6 Generátorové notace

6.7 Generátorové notace vs. funkce vyššího řádu map a filter

6.8 Uzávěry

6.9 Částečné vyhodnocené funkce

6.10 Curryfikace a částečné vyhodnocení funkcí

6.11 Kompozice funkcí

7 Dekorátory

7.1 Obalení funkcí bez využití dekorátorů

7.2 Obalení funkcí s využitím dekorátorů

7.3 Vyrovnávací paměť s výsledky čistých funkcí

8 Aplikace běžící ve více vláknech či procesech

8.1 Zajištění běhu aplikace ve více vláknech

8.2 Zajištění běhu aplikace ve více procesech

8.3 Komunikace mezi procesy

8.4 Spouštění a řízení souběžně a paralelně běžících úloh – concurrent.futures

8.5 Benchmark porovnávající různé varianty souběžných a paralelních výpočtů

9 Python a vývoj webových aplikací

9.1 Lze Python použít pro webový front-end?

9.2 Transpřekladače do JavaScriptu

9.3 Brython

9.4 PyScript

10 Novinky v ekosystému Pythonu

10.1 Správa projektů a virtuálních prostředí

10.2 Lintery

11 Závěr

12 Odkazy na další informační zdroje

1 Úvod

1 Úvod

Programovací jazyk Python v současnosti patří mezi nejpopulárnější a nejčastěji nasazované programovací jazyky. Přitom se jedná o univerzální jazyk, který je možné použít v mnoha aplikačních oblastech. Python tak nalezne své využití jak při psaní krátkých a jednoduchých skriptů umožňujících a zjednodušujících administraci systému, tak i pro vývoj složitějších utilit, ale i například pro tvorbu desktopových aplikací (zde se využívají knihovny PyQt, PySide, wxPython, Tkinter, PyGObject, Wax či PySimpleGUI), webových služeb, pro analýzu a zpracování dat, strojové učení (ML – machine learning) a umělou inteligenci (AI – artificial intelligence). Python je dokonce možné v případě potřeby použít i na front endu, tedy pro ty části webových aplikací, které jsou spouštěny přímo ve webových prohlížečích u klientů. A díky existenci projektu MicroPython se jazyk Python používá i pro programování mikrořadičů.

Samotný programovací jazyk Python se přitom po celou dobu své existence (to je více než třicet let!) neustále vyvíjí, protože jsou do něj postupně přidávány nové vlastnosti. Ovšem ve skutečnosti se nevylepšuje pouze samotný jazyk Python, ale i celý jeho ekosystém, do něhož patří knihovny, analytické nástroje, ladicí nástroje, správci projektů, správci virtuálních prostředí atd. V této knize se budeme zabývat jak novinkami, které byly postupně do Pythonu přidány, tak i nástroji, které okolo tohoto programovacího jazyka vznikly a jenž například umožňují výše zmíněné použití Pythonu ve webovém prohlížeči. Zmíníme se i o některých trendech, jimiž dnes „žije“ komunita vývojářů používajících tento programovací jazyk. Jedná se v první řadě o takzvané typové anotace, které postupně začalo využívat velké množství nástrojů a překladačů Pythonu.

2 Stručná historie vývoje Pythonu

2 Stručná historie vývoje Pythonu

V této kapitole se ve stručnosti seznámíme s historií vývoje programovacího jazyka Python, a to od samotných prvopočátků (vše začalo programovacím jazykem nazvaným ABC) až k nejnovější verzi Pythonu, což je v době psaní této knihy Python 3.12. Celá historie je, minimálně z pohledu IT, poměrně dlouhá, protože výše zmíněný programovací jazyk ABC byl poprvé vydán již v roce 1987, tedy vlastně v počítačovém středověku (počítačovým pravěkem můžeme označovat dobu první generace takzvaných mainframů v padesátých letech minulého století).

2.1 Předchůdce Pythonu: programovací jazyk ABC

Autorem programovacího jazyka Python je Guido van Rossum. Před samotným popisem vývoje jazyka Python se však pro úplnost zmiňme o ještě starším programovacím jazyku, který se jmenuje ABC. Práce na vývoji jazyka ABC začala již v polovině osmdesátých let minulého století v CWI (Centrum Wiskunde & Informatica), což je instituce sídlící v Nizozemsku. A právě na vývoji tohoto programovacího jazyka má svůj podíl i Guido, který zde pracoval společně s Lambertem Meertensem, Leo Geurtsem a Stevenem Pembertonem (mimochodem: zajímavé je, že Guido byl v té době na juniorské pozici). Cílem tohoto vývojového týmu bylo vytvořit nový programovací jazyk, který by byl dobře použitelný i lidmi, kteří sice nejsou profesionálními programátory, ale aplikace potřebují vytvářet a nějakým způsobem je i udržovat (jednou z cílových skupin byli pochopitelně vědci; ostatně nejedná se ani o první a ani o poslední programovací jazyk s podobnými ambicemi).

Na tomto místě je možná dobré si ve stručnosti připomenout, v jakém stavu se vlastně nacházela informatika v polovině osmdesátých let minulého století. Právě v této době totiž došlo k obrovskému (a z pohledu dalšího vývoje i revolučnímu) rozvoji v oblasti osmibitových domácích mikropočítačů i šestnáctibitových osobních mikropočítačů. A především domácím osmibitovým mikropočítačům kraloval jiný programovací jazyk určený pro širokou veřejnost a nikoli (pouze) pro profesionály.

Jednalo se o tehdy slavný BASIC (Beginners’ All-purpose Symbolic Instruction Code), což byl programovací jazyk, který existoval v mnoha navzájem nekompatibilních dialektech a taktéž většina těchto dialektů nepodporovala strukturované programování, pracovalo se v něm pouze s globálními proměnnými a i typový systém byl pro větší projekty neuspokojivý (a to vůbec nemluvíme o nepodpoře objektově orientovaného programování). Tyto vlastnosti do určité míry vycházely z toho, aby byl jazyk jednoduše pochopitelný a použitelný, ovšem navíc se vycházelo z požadavků, aby se celý interpret BASICu mohl uložit do 2kB, 8kB či v některých případech do 16kB ROM.

Pro zajímavost se podívejme na to, jak vypadá jednoduchý program zapsaný v nestrukturovaném BASICu:

1 REM
2 REM *****************************
3 REM 
4 REM Algoritmus bublinoveho razeni
5 REM 
6 REM Uprava pro Atari BASIC
7 REM 
8 REM *****************************
9 REM
10 DIM A(20)
11 FOR I=0 TO 20
12 A(I)=INT(100*RND(0))
13 NEXT I
14 GOSUB 100:REM TISK OBSAHU POLE
20 FOR I=19 TO 0 STEP -1
21 PRINT ".";
25 FOR J=0 TO I
30 IF A(J)<A(J+1) THEN X=A(J):A(J)=A(J+1):A(J+1)=X
35 NEXT J
40 NEXT I
49 PRINT ""
50 PRINT "SORTED:"
60 GOSUB 100:REM TISK OBSAHU POLE
99 STOP
100 REM TISK OBSAHU POLE
101 FOR I=0 TO 20
102 PRINT I,A(I)
103 NEXT I
104 RETURN 
998 REM finito
999 STOP

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/historie/bubble-sort.bas

Na rozdíl od (většinou) nestrukturovaného BASICu, který navíc programátorům nabízel pouze základní datové typy (typicky se jednalo jen o čísla, textové řetězce, jednorozměrná pole a matice) byl programovací jazyk ABC navržen odlišným, dnes bychom mohli říci, že mnohem modernějším způsobem (zdá se, že Meertens dokonce BASIC přímo nesnášel, jeho mottem totiž bylo „Stamp out Basic!“). Ostatně podívejme se na jednoduchý příklad programu napsaného v jazyce ABC, který získá všechna slova ze vstupního dokumentu. Můžeme zde vidět poměrně velkou podobnost s pozdějším Pythonem. Zejména je patrné, že odsazování řádků s programovým kódem je součástí syntaxe jazyka, dále zde nalezneme používání dvojteček, použití programové smyčky typu for-each, využití operátoru not.in apod.:

HOW TO RETURN words document:
   PUT {} IN collection
   FOR line IN document:
      FOR word IN split line:
         IF word not.in collection:
            INSERT word IN collection
   RETURN collection

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/historie/jazyk.abc

Malá poznámka k syntaxi jazyka ABC: slova HOW TO RETURN definují novou funkci, což vlastně znamená, že se jedná o obdobu k dnešnímu klíčovému slovu def. Referenční příručka celého jazyka ABC je dostupná na stránce https://homepages.cwi.nl/~steven/abc/qr.html.

2.2 Slibný začátek, ale pouze začátek

Ovšem nakonec se ukázalo, že svět IT nebyl na tento programovací jazyk připraven (někdo by dokonce mohl říci, že se jednalo o špatné načasování vstupu na trh, ovšem ABC nebyl vyvíjen na čistě komerční bázi). Na mikropočítačích s relativně malými systémovými zdroji nebylo možné potenciálu programovacího jazyka ABC využít a navíc mu v této oblasti velmi zdárně konkuroval jazyk BASIC, o kterém vycházely desítky, možná spíše i stovky knížek a který byl díky uložení přímo v paměti ROM logicky prvním jazykem většiny začátečníků (a popravdě řečeno: většina vlastníků domácích mikropočítačů o existenci ABC ani nevěděla).

Na druhé straně výkonnostního spektra, tedy typicky na počítačích s operačním systémem UNIX, se již používaly odlišné skriptovací jazyky, například programovací jazyk Tcl (1988) a Perl (1987). Na strojích vyráběných společností IBM se naproti tomu používal programovací jazyk Rexx (ten je dokonce ještě starší, protože pochází z roku 1979), ze kterého se později na slavné Amize vyvinul jazyk nazvaný ARexx. Nicméně i přes relativní neúspěch samotného jazyka ABC nebyly základní myšlenky v něm obsažené ztraceny, protože je později Guido van Rossum použil právě při implementaci první verze Pythonu, který z jazyka ABC v mnoha ohledech vycházel.

2.3 Odsazování řádků zdrojového kódu v jazycích ABC a Python

Zkušenější programátoři, kteří se poprvé seznamují s programovacím jazykem Python, bývají mnohdy překvapeni tím, že součástí syntaxe tohoto programovacího jazyka je i odsazení (tedy vlastně „prázdné“ znaky). Navíc se na začátku jednotlivých bloků kódu používá dvojtečka (naopak začátečníci, kteří jiný programovací jazyk neznají, tento fakt většinou zcela přirozeně přijmou). Na tomto místě si možná někdo položí otázku, kde se vlastně tento neobvyklý zápis programů objevil?

Dokonce ještě před samotným programovacím jazykem ABC bylo vytvořeno několik jeho předchůdců označovaných písmenem B a číslovkou (B0, B1, …). A již v jazyku se jménem B0 se objevilo povinné odsazování, které zde mělo význam sdružení jednotlivých operací (příkazů a dalších programových konstrukcí) do programových bloků. Ovšem samotné bloky tehdy byly uvozeny klíčovými slovy BEGIN a END. Plánovalo se, že díky použití klíčových slov bude odsazování prováděno automaticky ve specializovaném programátorském textovém editoru (což byla v době vzniku B0 relativně přelomová myšlenka, která byla prakticky realizována až o mnoho let později).

Poznámka: výše uvedená klíčová slova BEGIN a END ovšem známe například i z Pascalu nebo z programovacího jazyka Lua. Ovšem v těchto jazycích není odsazování striktně vyžadováno, na rozdíl od jazyka B.

Ovšem poté si tvůrci jazyka B0 uvědomili, že vyžadovat odsazení a současně navíc i použití klíčových slov BEGIN a END je vlastně nadbytečné a proto v jazyce B1 (tedy ve druhé variantě programovacího jazyka B) již chybělo klíčové slovo BEGIN (což znamená, že jsme již na půli cesty k Pythonu). Namísto klíčového slova END se používalo spojení dvou klíčových slov, například END IF, END FOR atd. To tedy znamená, že podmínky a programové smyčky automaticky vytvářely bloky, což je podle mého názoru dobrý způsob strukturování programů. A nakonec se v jazyce B2 (tedy v pořadí již v jeho třetí variantě) programátoři „museli“ zcela obejít bez zápisu začátků a konců bloků pomocí klíčových slov – vše již bylo vyřešeno pouhým odsazením.

Poznámka: na tomto místě je vhodné doplnit, že se odsazení pro specifikaci bloků se používalo i v jiných programovacích jazycích (Miranda atd.), ovšem jazyk B byl pravděpodobně prvním jazykem, kde k této implementaci došlo.

2.4 Dvojtečka zapisovaná na začátku bloků kódu

Dalším typickým prvkem programovacího jazyka B (a posléze i jazyků ABC a Python) je dvojtečka zapisovaná na začátku bloků kódu, což může v moderním Pythonu vypadat následovně (pro zajímavost je ukázán algoritmus bublinkového řazení, který jsme viděli i v BASICové variantě):

import random

size = 100

a = [random.randrange(0, 10000) for i in range(size)]

for i in range(size - 1, 0, -1):
    for j in range(0, i):
        if a[j] > a[j + 1]:
            a[j], a[j + 1] = a[j + 1], a[j]

print("Sorted:")
print(a)

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/historie/bubble-sort.py

Myšlenka na použití dvojtečky v tomto kontextu vznikla v roce 1978, kdy Robert Dewar, Peter King, Jack Schwartz a náš starý známý Lambert Meertens navrhovali syntaxi jazyka B a porovnávali různě zápisy bubble sortu (opět!). Nakonec zavolali manželku Roberta Dewara a zeptali se jí, zda se jí navržená varianta líbí. Ta odpověděla, že má pocit, že se zápis FOR i ... vztahuje pouze k jednomu řádku a nikoli k celému bloku pod tímto řádkem. A právě na základě tohoto alfa testingu návrhu nového programovacího jazyka bylo rozhodnuto před začátkem bloku používat dvojtečku, což Pythonu vydrželo až do současnosti a s velkou pravděpodobností se již měnit nebude.

Poznámka: to vlastně znamená, že dvojtečka před začátkem bloku (namísto závorek či klíčových slov) není v žádném případě novým a neobvyklým vynálezem; je s námi v IT již více než 40 let.

2.5 Další skriptovací jazyk na již obsazené nice?

Jak jsme se již zmínili v předchozím textu, vznikl programovací jazyk Python na samotném začátku devadesátých let minulého století. Z mnoha pohledů se jednalo o důležitý mezník v rozvoji informatiky, protože právě tehdy se začala stále více rozšiřovat myšlenka, že programovací jazyky určené pro vývoj plnohodnotných aplikací lze zhruba rozdělit do dvou kategorií – překládané systémové jazyky (compiled languages) a jazyky skriptovací (interpreted languages, což je však hrubě nepřesné).

Samozřejmě, že se skriptovací jazyky používaly i před tímto obdobím, ale většinou se jednalo o relativně primitivní formy předpisů pro dávkové úlohy (výjimkou je například již zmíněný jazyk Rexx, jehož vyjadřovací prostředky již byly na vysoké úrovni). A navíc převažoval názor, že plnohodnotné aplikace musí být psány v překládaných jazycích, tedy typicky v jazycích ALGOLské větve se statickým typováním (schválně nepíšu se silným typováním, to je sice související, ovšem odlišná vlastnost, ostatně k velmi důležité problematice datových typů se ještě vrátíme).

V průběhu devadesátých let se tedy zpočátku mírně opovrhované skriptovací jazyky staly mnohdy nedílnou součástí mnoha profesionálních aplikací. Celý vývoj v této oblasti a s ním související myšlenkový posun byl nakonec shrnut ve slavném článku Johna Ousterhouta „Scripting: Higher Level Programming for the 21st Century“, v  němž se opakovala myšlenka na souběžné a koopertivní použití dvou jazyků – systémového a skriptovacího. Mimochodem: John Ousterhout věděl, o čem píše, protože je autorem programovacího jazyka TCL.

Poznámka: do skupiny klasických skriptovacích jazyků z této doby lze zařadit právě Python, dále Perl, Tcl, Rexx, shell (resp. jeho různé varianty) a taktéž poněkud později vytvořený jazyk Ruby. Ovšem ze širšího pohledu můžeme skupinu rozšířit například i o programovací jazyk Lua nebo o JavaScript a jazyky nad ním postavené (což je například CoffeeScript atd.).

2.6 Od Pythonu 0.9.0 k Pythonu 3.12

Jazyk Python se vyvíjí již čtyři desetiletí. V této podkapitole se ve stručnosti zmíníme o některých důležitých milnících.

2.6.1 První verze programovacího jazyka Python

Prvotní verze Pythonu, tedy verze, které vyšly ještě před oficiálním vydáním 1.0, jsou vypsány v následující tabulce:

Verze

Datum vydání

0.9.0

20. února 1991

0.9.1

konec února 1991

0.9.2

podzim 1991

0.9.4

24. prosince 1991

0.9.5

2. ledna 1992

0.9.6

6. dubna 1992

0.9.8

9. ledna 1993

0.9.9

29. července 1993

Jak již čísla verzí napovídají, nejednalo se o stabilní produkt.

2.6.2 Python 1

První stabilní (zejména ve smyslu již zmíněné sémantiky) verze programovacího jazyka Python byla vydána v roce 1994 a verze 1.x byly postupně vydávány až do roku 2001 (!), v němž vyšla poslední jedničková verze 1.6.1, která celou řadu Python 1 uzavřela. V Pythonu 1 ještě pochopitelně nenalezneme všechny vlastnosti, které známe ze stále ještě částečně rozšířeného Pythonu 2 nebo Pythonu 3 (který dnes Python 2 postupně nahrazuje).

Například řetězce byly v Pythonu 1 čistě osmibitové (ASCII), zatímco už v Pythonu 2 bylo možné použít Unicode řetězce. Dále v Pythonu 1 nebyla podporována takzvaná generátorová notace a od ní odvozené konstrukce pro inicializaci seznamů, množin a slovníků. Taktéž ale neexistovaly ani operátory spojené s operací přiřazení, tedy například operátor +=, |= apod. Tyto varianty operátorů byly přidány až do Pythonu 2; inspirací byly v této oblasti pochopitelně především céčkové jazyky. A konečně, v Pythonu 1 neměly řetězce žádné metody, například string.startswith atd. – i tato funkcionalita byla přidána až v Pythonu 2.

V následující tabulce jsou vypsány všechny oficiálně vydané verze Pythonu 1:

Verze

Datum vydání

1.0.0

26. ledna 1994

1.0.2

15. února 1994

1.0.3

4. května 1994

1.0.4

14. července, 1994

1.1

11. října 1994

1.1.1

10. listopadu 1994

1.2

13. dubna 1995

1.3

13. října 1995

1.4

25. října 1996

1.5

3. ledna 1998

1.5.1

31. října 1998

1.5.2

13. dubna 1999

1.6

5. září 2000

1.6.1

25. února 2001

Poznámka: v současnosti, kdy verze nějakého frameworku nebo knihovny určené pro ekosystém jazyka JavaScript vydaná před dvěma týdny je mnohdy považována za zoufale zastaralou, se to může zdát zvláštní, ale stále se můžeme ve specifických případech setkat s použitím Pythonu verze 1. Konkrétně jsem viděl použití Pythonu 1.5.2 a 1.6.1. Ostatně není bez zajímavosti, že tyto verze jsou dostupné ve formě zdrojových kódů a jsou stále přeložitelné i na současných verzích Linuxu či systému Microsoft Windows (i když pro nové projekty vřele doporučuji používat Python 3).

2.6.3 Python 2

Vydání Pythonu 2.0 datujeme na 16. říjen 2000. Python 2 byl velmi úspěšným projektem, který do značné míry zajistil Pythonu místo na samotném vrcholu popularity programovacích jazyků. Ovšem již v roce 2008 vyšel Python 3.0 (založený na PEP 3000, což bylo někdy spojováno do označení „Python 3000“), který je s verzí 2 částečně nekompatibilní. A právě popularita a velké rozšíření Pythonu 2 a jeho balíčků na jedné straně a nekompatibilita Pythonu 3 na straně druhé zapříčinila více než desetileté schizma světa Pythonu, které je teprve postupně napravováno s tím, jak se stále více balíčků a aplikací portuje na Python 3 (a v některých oblastech ani zdaleka není ukončeno, nicméně všechny nejdůležitější knihovny jsou již nabízeny buď výhradně pro Python 3 nebo jak pro Python 2, tak i pro Python 3).

Poznámka: na druhou stranu je nutné poznamenat, že se přechod na Python 3 v mnoha oblastech podařil a to v mnoha případech relativně snadno. Nenastala tedy taková patová situace, jako v případě Perlu 5 vs. Perl 6 (v současnosti Raku).

Opět si pochopitelně vypíšeme data vydání různých verzí Pythonu 2 (bez „setinkových“ vydání:

Verze

Datum vydání

2.0

16. října 2000

2.1

17. dubna 2001

2.2

21. prosince 2001

2.3

29. července 2003

2.4

30. listopadu 2004

2.5

16. září 2006

2.6

1. října 2008

2.7

3. července 2010

Žádná z těchto verzí Pythonu již není oficiálně podporována a doporučuje se, aby všechny nové projekty vznikaly již pro Python 3.

2.6.4 Python 3

Python 3.0, tedy první verze Pythonu řady 3, byla vydána v prosinci 2008. Za zmínku stojí „překryv“ v současném vydávání Pythonu 2.x a 3.x. Většina informací z této knihy se vztahuje právě k novějším verzím Pythonu 3.x:

Verze

Datum vydání

3.0

3. prosince 2008

3.1

27. června 2009

3.2

20. února 2011

3.3

29. září 2012

3.4

16. března 2014

3.5

13. září 2015

3.6

23. prosince 2016

3.7

27. června 2018

3.8

14. října 2019

3.9

5. října 2020

3.10

4. října 2021

3.11

24. října 2022

3.12

2. října 2023

Povšimněte si velké pravidelnosti ve vydávání verzí, ke které došlo od verze 3.8. Příští plánovaná verze bude 3.13 a vyjít by měla letos, a to opět v říjnu.

2.7 Popularita Pythonu

V současnosti patří programovací jazyk Python mezi nejpopulárnější programovací jazyky vůbec. Nachází se na předních místech v mnoha statistikách, z nichž jmenujme například:

Tiobe index dostupný na adrese https://www.tiobe.com/tiobe-index/

PYPL PopularitY of Programming Language dostupný na adrese
https://pypl.github.io/PYPL.html

Top 10 programming languages na GitHubu dostupný na adrese
https://github.blog/2023-11-08-the-state-of-open-source-and-ai/

3 Rozsáhlý svět programovacího jazyka Python v současnosti

3 Rozsáhlý svět programovacího jazyka Python v současnosti

Pod označením Python si většina vývojářů představí jak konkrétní verzi interpretru Pythonu, včetně jeho základních knihoven, tak i de facto standard tohoto programovacího jazyka. V rámci jednotlivých vydání interpretru Pythonu se totiž do tohoto jazyka přidávají další nové vlastnosti s&nbps;tím, že ostatní implementace Pythonu (o nichž pochopitelně bude řeč v dalších podkapitolách) tyto změny postupně akceptují a taktéž je implementují (i když je nutno upozornit na to, že většinou s větším či menším zpožděním).

Původní interpretr programovacího jazyka Python se z důvodu rozlišení mezi programovacím jazykem a jeho jednou (i když referenční) implementací dnes nazývá CPython (toto označení vychází z faktu, že tento interpret je naprogramován v jazyku C). Kromě CPythonu ovšem máme v současnosti k dispozici i více či méně kvalitní překladače programovacího jazyka Python, a to jak AOT (Ahead Of Time) překladače, tak i JIT (Just In Time) překladače. Navíc existují i další varianty Pythonu určené pro běh na virtuálních strojích Javy popř. na virtuálním stroji s CLR (tedy .NET). A aby toho nebylo málo, lze Python poměrně úspěšně provozovat i ve webovém prohlížeči.

Svět programovacího jazyka Python je tedy poměrně rozsáhlý a pravděpodobně se (možná vedle Scheme, LISPu i již zmíněného jazyka BASIC) jedná o jazyk s nejvíce různorodými implementacemi vůbec. A právě s některými zajímavými implementacemi Pythonu se ve stručnosti seznámíme v této kapitole.

3.1 Standardní interpretr Pythonu: de facto standard jazyka

V současnosti je vyvíjeno či alespoň udržováno pouze pět verzí Pythonu (tedy, jak již víme, přesněji řečeno CPythonu). Jedná se o následující verze:

Verze

Stav

3.8

security

3.9

security

3.10

security

3.11

bug fix

3.12

bug fix

Pro ty verze Pythonu (CPythonu), které se nachází ve stavu security, se oficiálně vydávají pouze zdrojové kódy, do nichž jsou přidávány jen nové bezpečnostní opravy, ovšem nikoli již opravy jiných chyb (a už vůbec ne nějaká další vylepšení a nové vlastnosti). To znamená, že překlad binárních balíčků v takovém případě provádí například autoři distribucí operačních systémů (Linux) atd. Naproti tomu novější verze nacházející se ve stavu bug fix jsou vydávány i v binární podobě a jsou do nich postupně zahrnovány i opravy běžných chyb.

Co to ovšem znamená v praxi? Zejména na produkčních systémech by měly být provozovány pouze udržované verze Pythonu, což dnes konkrétně znamená Python 3.8 či vyšší (a to za předpokladu, že pro použitý operační systém nebo pro jeho distribuci jsou skutečně ještě vydávány bezpečnostní opravy). To ovšem není vše. Pokud to pochopitelně okolnosti dovolí, je dnes vhodné používat verzi 3.11 či 3.12, protože pro tyto verze jsou vydávány opravy všech chyb. A navíc, jak uvidíme v dalším textu, došlo ve verzi 3.11 k poměrně významnému urychlení standardního interpretru Pythonu, což znamená, že například služby naprogramované v Pythonu budou vyžadovat méně zdrojů (CPU) popř. mohou být jednotlivé úkoly dokončeny rychleji. I to může být jeden z důvodů přechodu na novější verzi.

V praxi, konkrétně při nasazování různých verzí Pythonu i při plánování jejich případného upgrade, je taktéž dobré sledovat termíny, do kterých bude daná verze Pythonu oficiálně podporována. Pro všech pět v současnosti podporovaných verzí Pythonu jsou tyto termíny naplánovány následovně:

Verze

Podpora do

3.8

říjen 2024

3.9

říjen 2025

3.10

říjen 2026

3.11

říjen 2027

3.12

říjen 2028

Poznámka: nové verze Pythonu (CPythonu) jsou vydávány s frekvencí přibližně jedné verze do roka. To je poměrně nízká frekvence, která dává vývojářům, DevOps týmům či administrátorům dostatek času na přechod na vyšší verzi. Některé jiné programovací jazyky naproti tomu vychází s větší frekvencí. Příkladem může být programovací jazyk Go, jehož nové verze jsou vydávány dvakrát do roka (viz například https://go.dev/doc/devel/release).

3.2 Varianty Pythonu určené pro běh ve virtuálních strojích

Standardní CPython je dodáván ve formě nativního spustitelného souboru (popř. skriptu, který takový soubor spouští). Ovšem můžeme se setkat i s implementacemi Pythonu určenými pro běh ve virtuálních strojích. Konkrétně se jedná o JVM a CLR, tedy o virtuální stroje Javy (a celého ekosystému postaveného okolo Javy) a o .NET. Pro tyto virtuální stroje vznikl Jython a Iron Python.

3.2.1 Jython

Jython je jednou z implementací programovacího jazyka Python určená pro běh v rámci virtuálního stroje Javy (JVM - Java Virtual Machine). A nejenom to. Navíc totiž aplikace psané v Jythonu mohou velmi dobře kooperovat s třídami (class) a rozhraními (interface) vytvořenými v Javě, což je v praxi mnohdy velmi výhodné, protože s rostoucí složitostí moderních aplikací je většinou zapotřebí mít k dispozici vhodný skriptovací jazyk sloužící jako „lepidlo“ (glue) mezi jednotlivými stavebními bloky, z nichž se taková aplikace skládá.

Jython ovšem samozřejmě není dokonalý. Jednou z jeho velkých nevýhod je fakt, že je stále postaven na dnes již obstarožním Pythonu 2, druhou nevýhodou pak ta skutečnost, že se jedná o dosti pomalý jazyk (a to i v porovnání se standardním CPythonem). Tato pomalost se negativně projeví zejména při výpočtech a někdy i při manipulaci s rozsáhlými datovými strukturami, ovšem u aplikací, v nichž převládají I/O operace se ne vždy musí jednat o kritický nedostatek.

3.2.2 Iron Python

Zatímco výše zmíněný Jython je varianta Pythonu určená pro běh v rámci virtuálního stroje Javy, je Iron Python pro změnu implementován pro prostředí .NET popř. Mono. Samotný Iron Python je naprogramován v jazyce C#, zatímco původní Python je vytvořen, jak již víme, v jazyku C. Iron Python je v současnosti nabízen ve dvou verzích: 2.7 (kompatibilita s originálním Pythonem 2.7) a taktéž ve verzi 3.4 (v době psaní této knihy konkrétně ve verzi 3.4.1). Velkou předností Iron Pythonu je jeho výborná integrace s knihovnami pro .NET/Mono, a to včetně knihovny pro tvorbu grafického uživatelského rozhraní atd.

Poznámka: zajímavé je, že původní autor Jythonu i Iron Pythonu je jedna a tatáž osoba: Jim Hugunin.

3.3 Překladače Pythonu

U standardního interpretru Pythonu (CPython) se zdrojové kódy před spuštěním překládají do bajtkódu (bytecode) a tento bajtkód je následně interpretován. To je, zcela podle očekávání, poměrně pomalé. Z tohoto důvodu postupně vznikly překladače (compiler) zajišťující překlad zdrojových kódů napsaných Pythonu do více či optimálně vygenerovaného nativního (strojového) kódu. Takový překlad je možné provést v jediném kroku nebo ve více fázích (potom typicky rozlišujeme frontend a backend překladače). Navíc se od sebe jednotlivé překladače liší podle toho, zda je překlad proveden ještě před samotným spuštěním aplikace (AOT – Ahead Of Time) nebo až ve chvíli, kdy se načítají jednotlivé balíčky nebo když se detekuje takzvaná „horká“ část kódu (JIT – Just In Time). Každý ze zmíněných způsobů, tedy interpretace bajtkódu, JIT překlad a AOT překlad, má své výhody a zápory a obecně pravděpodobně není možné bez znalosti vlastností konkrétního projektu říci, který z nich je obecně výhodnější. Vše záleží na konkrétním způsobu použití.

3.3.1 PyPy

PyPi je typickým představitelem Just in Time překladače. Zdrojový kód je tedy interpretován (spouštěn) a současně i analyzován. V okamžiku, kdy se nalezne taková sekvence kódu, kterou by bylo vhodné přeložit, je proveden překlad. Typicky se jedná o často volané funkce a především pak o (vnitřní) programové smyčky. Toto chování umožňuje reagovat na situaci, kdy se například nějaká funkce volá s různými typy argumentů a mění tak své chování. Taková funkce může být v případě potřeby přeložena v několika variantách. Určitou nevýhodou JIT překladače PyPy je fakt, že není stoprocentně kompatibilní s CPythonem. Některé programy lze v PyPi používat naprosto bez problémů (budou „jen“ mnohem rychlejší, což samozřejmě všichni uvítají), ale v dalších situacích budou nutné větší či menší úpravy projektu. Zajímavé je, že část PyPi je naprogramována v dále zmíněném RPythonu.

3.3.2 Numba

Numba je projekt primárně umožňující překlad kódu v době běhu aplikace, tedy v runtime. Jedná se tedy o Just In Time překladač, který má tu výhodu, že dokáže poměrně efektivně odvodit datové typy proměnných a parametrů funkcí na základě skutečného chování aplikace. To samozřejmě neznamená, že by JIT již při prvním volání nějaké funkce přesně věděl, jakým způsobem má tuto funkci přeložit. Ve skutečnosti se dozví pouze informace o jediné konkrétní větvi, kterou může přeložit. V případě, že bude ta samá funkce později volána s odlišnými typy argumentů, popř. se její chování změní jiným způsobem (Python je v tomto ohledu velmi dynamický jazyk), provede se just-in-time překlad znovu, takže zde zaplatíme za vyšší výpočetní výkon poněkud většími paměťovými nároky a pomalejším během prvních volání funkce (či celého projektu).

Z pohledu běžného vývojáře je největší předností tohoto způsobu překladu fakt, že není zapotřebí samotný zdrojový kód modifikovat (až na uvedení anotace před funkci). Nepříjemný je přesun času překladu do času běhu projektu, což sice nevadí u aplikací, které běží delší dobu, ovšem u jednorázových skriptů může být použití JITu spíše kontraproduktivní (vše je nutné v praxi ověřit pomocí benchmarků).

Samotný překlad je prováděn na několika úrovních, přičemž Numba na nižších úrovních využívá možností nabízených překladačem LLVM.

Nástroj Numba ovšem poskytuje i alternativní způsob překladu. Jedná se o již několikrát zmíněný AOT (Ahead Of Time) překlad, který ovšem vyžaduje informovat Numbu o datových typech parametrů a proměnných, podobně jako je tomu v Cythonu nebo v dále zmíněném nástroji mypyc. V tomto ohledu se Numba do značné míry podobá dále zmíněnému překladači mypyc.

3.3.3 mypyc

Klasickým příkladem AOT (Ahead Of Time) překladače Pythonu je nástroj nazvaný mypyc. Tento nástroj je součástí instalace Mypy, viz též pátou kapitolu celou věnovanou typovým informacím. Nástroj mypyc pracuje přibližně následujícím způsobem:

Je provedena analýza původního Pythonovského zdrojového kódu s jeho překladem do AST (abstraktního syntaktického stromu)

Na základě AST (s typy) je vygenerován zdrojový kód reprezentovaný v jazyku C

Takto vygenerovaný kód je přeložen překladačem céčka (typicky se používá gcc, LLVM atd.)

Výsledkem je sdílená knihovna strukturovaná takovým způsobem, že ji lze využít jako takzvané C-extension jazyka Python (lze ji přímo volat ze skriptů Pythonu)

Výslednou sdílenou knihovnu (DLL či so) je posléze umožněno naimportovat do Pythonovského skriptu. Odpovídá totiž již zmíněné specifikaci C-extension. Na rozdíl od dalších AOT překladačů tedy není výsledkem přímo spustitelný soubor, což opět přináší některé přednosti, ale i zápory (mezi zápory patří poněkud složitější spouštění).

3.3.4 RPython

RPython získal své jméno ze sousloví „Restricted Python“, přičemž všechna omezení (restrictions), která RPython zavádí, jsou pečlivě vybrána z toho důvodu, aby se zjednodušila či vůbec umožnila automatická statická analýza ®pythonovského kódu, který je překládán do nativního (objektového) kódu. Striktně řečeno tedy RPython není „skutečným“ Pythonem, protože ne všechny jazykové konstrukce standardního Pythonu jsou podporovány i v RPythonu. A omezení se kromě samotného jazyka týká i knihoven – RPython ani zdaleka neobsahuje celou standardní knihovnu Pythonu.

RPython se typicky používá primárně pro psaní interpretrů dalších programovacích jazyků. Ve skutečnosti je však možné v případě potřeby RPython použít i pro vlastní projekty, ovšem musíme se smířit s některými omezeními a problémy při snaze používat celý ekosystém postavený okolo Pythonu. Ovšem například v situaci, kdy máme naprogramován a odladěn nějaký výpočet v Pythonu, může být zajímavé ho přeložit RPythonem a využít tak toho, že výsledkem bude relativně dobře optimalizovaný nativní kód. Nicméně pro běžné účely je výhodnější použít jiný nástroj (viz již zmíněné nástroje Numba, mypyc, PyPy atd.).

3.3.5 Cython

Jedním z nejznámějších a pravděpodobně i nejpoužívanějších projektů, které se zaměřují na překlad Pythonu do nativního kódu, patří nástroj nazvaný Cython (pozor: neplést s podobně pojmenovaným CPythonem, což je, jak již dobře víme, označení klasického interpretru Pythonu). Tento překladač pracuje poněkud odlišným způsobem než výše zmíněný RPython. Zatímco se totiž RPython snaží odvozovat datové typy proměnných, parametrů i návratových hodnot funkcí na základě analýzy grafu (CFG), používá Cython přímý překlad Pythonu do programovacího jazyka C.

Ve chvíli, kdy Cython z nějakého důvodu nemá k dispozici informaci o datovém typu funkce/proměnné/parametru, použije PyObject *, tedy ukazatel na datovou strukturu reprezentující v klasickém Pythonu libovolnou hodnotu. V dalším kódu je samozřejmě nutné z tohoto objektu získat skutečnou hodnotu. I takto vlastně velmi primitivně provedený překlad dokáže ve skutečnosti výsledný kód přeloženého projektu zrychlit, což je ostatně patrné i na výsledku benchmarků, o nichž se zmíníme dále.

Cython jde ale ještě dále, protože rozšiřuje syntaxi programovacího jazyka Python o další klíčová slova, především pak o klíčové slovo cdef. Toto klíčové slovo je možné použít pro přesnou specifikaci typu proměnné či parametru, a to způsobem, který plně vychází z programovacího jazyka C. Tato typová informace samozřejmě umožňuje provedení dalších optimalizací ve výsledném kódu (opět lze vidět na výsledcích benchmarků uvedených v dalších částech knihy).

3.4 Python ve webových prohlížečích

Programovací jazyk Python se často využívá i při tvorbě webových služeb a webových aplikací. V této oblasti se Python nasazuje především na back endu, tj. pro tu část webové služby popř. aplikace, která je provozována na serveru a nějakým způsobem komunikuje s ostatními komponentami vytvářeného systému: front endem (typicky webový prohlížeč s interpretrem JavaScriptu), databází a dalšími (mikro)službami, například s využitím message brokerů, systémů pro monitoring a správu událostí atd. Tato oblast informatiky samozřejmě není pokryta pouze Pythonem, ale najdeme zde i mnohé další programovací jazyky a technologie, zejména Javu (a celý její middleware), JavaScript či TypeScript (node.js) a dnes taktéž programovací jazyk Go.

Zatímco pozice Pythonu v oblasti back endu je poměrně zřejmá, je situace na front endu mnohem složitější. Důvod je jednoduchý – v této oblasti z historických důvodů kraluje JavaScript, přičemž veškeré snahy a náhradu tohoto programovacího jazyka byly prozatím neúspěšné (pokusů bylo hned několik, připomeňme například dnes již pozapomenuté webové prohlížeče s podporou jazyků TCL, VBSCript či projekt Dark. Ovšem stále se můžeme setkat se snahami JavaScript nepoužívat přímo, popř. ho obejít s využitím jiných nástrojů. Příkladem mohou být technologie umožňující tvorbu webových aplikací podobným způsobem, jakoby se jednalo o aplikace desktopové.

3.4.1 Brython

Pro vývoj webových aplikací lze v některých případech využít nástroj nazvaný Brython. Jedná se o takzvaný transpřekladač (transcompiler, transpiler) z Pythonu do JavaScriptu, přičemž samotný překlad (resp. přesněji řečeno transpřeklad) probíhá na pozadí. To v praxi znamená, že přímo v kódu webové stránky je umístěn (či načítán) kód v Pythonu. Výhodou Brythonu je, že se jakékoli úpravy ihned projeví v aplikaci po znovunačtení stránky (stisk klávesy F5 ve webovém prohlížeči). Není tedy vyžadován explicitní krok s voláním (trans)překladače.

3.4.2 Transcrypt

Transcrypt je taktéž transpřekladačem Pythonu (konkrétně Pythonu 3) do JavaScriptu. Samotný transpřeklad je napsaný velmi kvalitně, takže lze zhruba odhadnout, že velikost vygenerovaného kódu v JavaScriptu odpovídá velikosti původního kódu napsaného v Pythonu (případné zvětšení je o jednotky procent). Musíme však počítat s tím, že je nutné načíst i jádro Transcriptu, jehož velikost je přibližně 20 kB. Tedy čím větší je kód samotné aplikace, tím (poměrově) menší budou režijní náklady. Zajímavá a užitečná je i podpora type hintů (informací o datovém typu parametrů, proměnných).

3.4.3 PyScript

PyScript je realizován tak, že se zdrojové kódy standardního CPythonu přeloží do WebAssembly (WASM), jenž je doplněn podpůrnými skripty naprogramovanými v JavaScriptu. Výsledkem je Python spustitelný ve webovém prohlížeči. Podobným způsobem lze namísto CPythonu použít i MicroPython.

Poznámka: s projekty Brython a PyScript se ještě setkáme v deváté kapitole.

3.5 MicroPython

MicroPython představuje alternativní implementaci Pythonu naprogramovanou taktéž v programovacím jazyku C, podobně jako standardní CPython. Ovšem již název tohoto projektu napovídá, že se jedná o variantu Pythonu určenou pro běh na šestnáctibitových a 32bitových mikrořadičích, které mají omezený jak výpočetní výkon, tak i kapacitu ROM a RAM (v tomto kontextu se bavíme například o desítkách či stovkách kilobajtů a nikoli o jednotkách a desítkách gigabajtů). Mj. i z tohoto důvodu je syntaxe a sémantika omezena tak, že je MicroPython sice kompatibilní s Pythonem 3.4 (a částečně i Pythonem 3.5), ovšem většinu nových vlastností, které budou popsány ve čtvrté kapitole, zde již nenajdeme.

4 Postupné rozšiřování syntaxe a sémantiky Pythonu

4 Postupné rozšiřování syntaxe asémantiky Pythonu

Programovací jazyk Python patří mezi živé jazyky, které se neustále vyvíjí. To ovšem znamená, že se postupně rozšiřuje avylepšuje nejenom jeho standardní knihovna, rychlost samotného interpretru, ale ijeho syntaxe asémantika. Ovšem co vlastně slova syntaxe asémantika vtomto kontextu znamenají?

Slovem syntaxe vinformatice označujeme ucelenou avětšinou ivelmi přesně definovanou sadu pravidel, kterými je specifikován způsob zápisu programů vurčitém programovacím jazyce. Popis syntaxe zahrnuje mj.ivýčet klíčových slov (těch vsoučasné verzi Pythonu existuje 35). Syntaxe tedy popisuje, jak zápis programů vypadá. Naproti tomu sémantika popisuje význam jednotlivých klíčových slov, operátorů, výrazů apříkazů (popis sémantiky většinou již není tak rigorózní, jako popis syntaxe). Obecně platí, že změna či rozšíření sémantiky nějakého jazyka sice může být sice poněkud méně viditelná, ale oto je vpraxi důležitější avýznamnější zhlediska vlastností programovacího jazyka.

Vraťme se však ksamotnému programovacímu jazyku Python. Vtéto kapitole se budeme zabývat především těmi novými prvky jazyka, které byly přidány ve verzích 3.5 až 3.12. Podívejme se nejdříve ve stručnosti, ojaké nové vlastnosti se vlastně jedná. Nové syntaktické asémantické prvky přidané vPythonu 3.5 až 3.12 jsou vypsány vnásledující tabulce:

Verze Pythonu

Nové vlastnosti

Python 3.5

sémantika pro async a await, operátor @, unpack

Python 3.6

f-řetězce, async-IO

Python 3.7

rezervovaná klíčová slova async a await

Python 3.8

mroží operátor, poziční parametry funkcí

Python 3.9

generické datové typy

Python 3.10

pattern matching

Python 3.10

možnost použití operátoru | při definici typů

Python 3.11

skupiny výjimek

Python 3.12

klíčové slovo type + jeho sémantika

Python 3.12

nová syntaxe pro zápis generických typů

Poznámka: informace oklíčových slovech async aawait vPythonu 3.5 je zde ve skutečnosti pouze orientační, protože plnohodnotnými rezervovanými klíčovými slovy se staly až ve verzi 3.7. Pro podrobnější informace viz následující podkapitoly.

4.1 Formátovací řetězce

Do programovacího jazyka Python byla vrámci nových vlastností verze 3.6 byla přidána podpora pro takzvané formátovací řetězce neboli zkráceně f-řetězce (f-strings). Tato nová konstrukce zjednodušuje formátování dat, která se mají vytisknout na standardní výstup, zobrazit na HTML stránce, zobrazit vgrafickém uživatelském rozhraní nějakého projektu sGUI atd. Tyto operace typicky znamenají že se musí nějakým způsobem zkombinovat statický textový obsah shodnotami proměnných, atributy objektů atd.

Formátovací řetězce doplňují arozšiřují metodu format definovanou pro datový typ řetězec (str). Připomeňme si, jak se vlastně tato metoda používá:

#Formátovánívýstupusvyužitímmetodystr.format

a=1
b=2
c=a+b

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print("{}+{}={}".format(a,b,c))

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/string-format.py

Formátovací řetězce se zapisují podobně jako běžné řetězce, tj.jsou zapsané do apostrofů nebo uvozovek, popř.do trojitých apostrofů nebo uvozovek (víceřádkové řetězce). Ovšem oproti běžným řetězcům začínají formátovací řetězce prefixem f zapsaným před samotným řetězcovým literálem (konstantou) aprávě ztohoto důvodu se vpůvodní anglické dokumentaci oprogramovacím jazyce Python tyto řetězce nazývají f-strings.

Poznámka: to, že do programovacího jazyka Python byla přidána podpora pro formátovací řetězce, ovšem vžádném případě neznamená, že už není povoleno použít původní způsoby formátování výstupů. Ty jsou pochopitelně stále dostupné azáleží pouze na vás, zda formátovací řetězce budeme chtít použít či nikoli. Můžeme pochopitelně použít ipřetížený operátor %:

#Formátovánívýstupusvyužitímpřetíženéhooperátoru%

a=1
b=2
c=a+b

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print("%d+%d=%d"%(a,b,c))

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/percent-operator.py

Poznámka: vdalších kapitolách si představíme nástroj Mypy, který nás vpřípadě správného nastavení upozorní na to, ve kterých místech programového kódu by bylo vhodné namísto starších metod formátování řetězců použít f-řetězce.

4.1.1 Základní použití formátovacích řetězců pro tzv. interpolaci proměnných

Podívejme se nyní na jeden znejjednodušších způsobů využití formátovacích řetězců. Vnásledujícím skriptu napsaném vPythonu nejdříve nadeklarujeme tři proměnné aposléze vypíšeme hodnoty všech třech proměnných, ato podle šablony (template), která vypadá následovně:

f"{a}+{b}={c}"

Znaky a, b aa(které představují názvy proměnných) jsou všabloně zapsány mezi složené závorky aztohoto důvodu jsou při konstrukci výsledného řetězce tyto znaky nahrazeny za hodnotu proměnných se stejným jménem:

#FormátovacířetězcevPythonu:
#-formátovánívýstupuzaloženénaf-řetězci
#-dosazeníhodnotproměnnýchdovýslednéhořetězce

a=1
b=2
c=a+b

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"{a}+{b}={c}")

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/f-string-1.py

Po spuštění tohoto skriptu se na terminálu zobrazí následující text:

1+2=3

4.1.2 Chování Pythonu vpřípadě, že se neuvede prefix „f“

Povšimněte si, že vpředchozím skriptu je před řetězovým literálem skutečně uveden znak f (takzvaný prefix). Vpřípadě, že tento prefix neuvedeme (například na to zapomeneme), nebude formátování (tedy výše zmíněná „interpolace“ proměnných) provedeno, protože řetězec bez prefixu f programovací jazyk Python považuje za běžný řetězcový literál. Ostatně si toto chování můžeme velmi snadno otestovat:

#FormátovacířetězcevPythonu:
#-chováníPythonuvpřípadě,žesepoužijeběžnýřetězec
#anikolif-řetězec

a=1
b=2
c=a+b

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print("{a}+{b}={c}")

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/f-string-2.py

Po spuštění takto upraveného skriptu se zobrazí původní řetězec:

{a}+{b}={c}

Poznámka: to tedy znamená, že přidáním f-řetězců do Pythonu se nenarušila kompatibilita se staršími zdrojovými kódy.

4.1.3 Výrazy ve formátovacím řetězci

Zajímavé ataktéž užitečné je, že ve formátovacím řetězci mohou být uvedeny nejenom názvy proměnných, ale isložitější výrazy. To například znamená, že výpočet součtu hodnot proměnných aab nemusíme ukládat do nové pomocné proměnné c, ale namísto toho můžeme součet zapsat přímo do formátovacího řetězce. Upravený skript vypadá následovně:

#FormátovacířetězcevPythonu:
#-výrazpoužitývf-řetězci

a=1
b=2

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"{a}+{b}={a+b}")

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/f-string-3.py

Výsledek vytištěný na terminál po spuštění tohoto skriptu:

1+2=3

4.1.4 Podmínka ve výrazu zapsaném ve formátovacím řetězci

Vprogramovacím jazyku Python je umožněno do výrazu zapsat ipodmínku (vněkterých jiných jazycích je pro tento účel použit takzvaný ternární operátor popř.tuto možnost vůbec nemají). Ztohoto důvodu lze podmínku zapsat ido formátovacího řetězce, ikdyž je vhodné upozornit na to, že výsledek už nemusí být příliš čitelný. Na druhou stranu lze tímto způsobem realizovat jednoduchý šablonovací systém:

#FormátovacířetězcevPythonu:
#-výrazspodmínkoupoužitývf-řetězci

a=1
b=-1

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"Kladné:{'ano'ifa>0else'ne'}")

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"Kladné:{'ano'ifb>0else'ne'}")

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/f-string-4.py

Po spuštění tohoto skriptu by se na terminál měla vypsat následující dvojice zpráv:

Kladné:ano
Kladné:ne

4.1.5 Volání funkce ve formátovacím řetězci

Vzhledem ktomu, že se volání funkce může objevit vběžném výrazu, znamená to, že volání funkce lze realizovat ive formátovacím řetězci. Opět ovšem platí, že výsledkem nemusí být příliš čitelný programový kód (anavíc, což může vadit více, nemusí být takový kód rozeznán akontrolován integrovanými vývojovými prostředími):

#FormátovacířetězcevPythonu:
#-volánífunkcevf-řetězci

x="Helloworld!"

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"Délkařetězce'{x}'je{len(x)}znaků")

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/f-string-5.py

Po spuštění takto upraveného skriptu by se měla spočítat délka řetězce uloženého vproměnné x anásledně by se tato délka měla použít při formátování zprávy zobrazené na terminálu:

Délkařetězce'Helloworld!'je12znaků

4.1.6 Volání metody vf-řetězci

Podobně jako uvolání funkcí můžeme přímo vrámci formátovacího řetězce realizovat volání metody nějakého objektu. Vnásledujícím skriptu je ukázán způsob zavolání metody nazvané capitalize pro instanci třídy řetězec (str). Tato metoda převede první znak ve větě na velké písmeno (verzálku):

#FormátovacířetězcevPythonu:
#-volánímetodyvf-řetězci

x="helloworld!"

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"Důležitázprávaprovás:'{x.capitalize()}'")

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/f-string-6.py

Výsledná zpráva zobrazena na terminálu bude vypadat následovně:

Důležitázprávaprovás:'Helloworld!'

4.1.7 Jednodušší ladění

Pro ladění programů vyvíjených vPythonu je možné využít různé prostředky (ostatně se sněkterými znich seznámíme vdalším textu), ovšem mnohdy je zdaleka nejsnazší si nechat vypsat obsah zvolených sledovaných proměnných, ideálně isjejich názvy. Ipro tento úkol je možné využít formátovací řetězce, protože pokud vřetězci použijeme zápis {proměnná=}, vloží se do výsledného řetězce jak název proměnné, tak ijejí hodnota. Podívejme se opět na jednoduchý demonstrační příklad, vněmž si necháme vypsat název ihodnotu proměnných se jmény name asurname:

#FormátovacířetězcevPythonu:
#-výpisjménaproměnnéspolečněsjejíhodnotou

name="Guido"
surname="Rossum"

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"{name=}{surname=}")

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/f-string-7.py

Výsledná zpráva zobrazená na terminálu by měla vypadat takto:

name='Guido'surname='Rossum'

4.1.8 Zarovnání hodnot ve výsledném naformátovaném řetězci

Při formátování hodnot, které mají být například součástí tabulek, vyvstává další problém: jak jednotlivé hodnoty zarovnat. Ipro tento úkol je možné využít formátovací řetězce, protože za jméno proměnné či za výraz lze vpřípadě potřeby zapsat jak jeho požadovanou délku ve výsledku (například deset znaků), ale ito, zda má být daná hodnota zarovnána doleva, doprava či na střed. Pro tento účel lze ve formátovacím řetězci použít následující zápis:

f"{výraz:zarovnáníšířka}

Pro specifikaci zarovnání se používají znaky < pro zarovnání doleva, ^ pro vycentrování a> pro zarovnání doprava. Navíc je možné pro numerické hodnoty použít iznak =, který zajistí přidání výplně mezi znaménko a(kratší) numerickou hodnotu (podobně je tomu například vtabulkových procesorech). Aspecifikace šířky určuje počet znaků rezervovaných ve výsledném řetězci pro výpis hodnoty výrazu. Pokud je hodnota výrazu kratší, než zadaná šířka, je výraz zarovnán adoplněn mezerami (popř.učísel typicky nulami).

Podívejme se na příklad, vněmž budeme realizovat zobrazení tabulky obsahující tři sloupce. Vtéto tabulce bude vypsán počet dětí, které se narodily suvedeným jménem (avyjadřuje tedy oblíbenost jmen). Hodnoty vprvním sloupci jsou vycentrovány (tedy zarovnány na střed), hodnoty ve druhém sloupci jsou zarovnány doprava akonečně hodnoty ve sloupci třetím jsou zarovnány doleva:

#FormátovacířetězcevPythonu:
#-specifikacešířkyhodnoty
#-specifikacezarovnáníhodnoty
#-výpistabulkyspopularitoujmen

jmena=("Eliška","Tereza","Anna","Adéla","Natálie","Hana")
narozeni=(2332,1900,1708,1535,1386,287)

#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"{'Pořadí':^10}{'Jméno':<10}{'Narození':>10}")

fori,(jmeno,nar)inenumerate(zip(jmena,narozeni)):
#výpisobsahuřetězcepodoplněníhodnotdlešablony
print(f"{i:^10}{jmeno:<10}{nar:>10}")

Zdrojový kód tohoto příkladu můžete najít na adrese
https://github.com/tisnik/Evoluce_Pythonu_priklady/blob/master/f-strings/f-string-8.py

Atakto vypadá tabulka po svém zobrazení na terminálu:

4.1.9 Naformátování numerických hodnot

Výsledkem bude tato tabulka:

Zobrazení hodnoty vprocentech

či:

1.

&

tuple

list

dict

set

frozenset

collections.deque

collections.defaultdict

collections.OrderedDict

collections.Counter

collections.ChainMap

collections.abc.Awaitable

collections.abc.Coroutine

collections.abc.AsyncIterable

collections.abc.AsyncIterator

collections.abc.AsyncGenerator

collections.abc.Iterable

collections.abc.Iterator

collections.abc.Generator

collections.abc.Reversible

collections.abc.Container

collections.abc.Collection

collections.abc.Callable

collections.abc.Set

collections.abc.MutableSet

collections.abc.Mapping

collections.abc.MutableMapping

collections.abc.Sequence

collections.abc.MutableSequence

collections.abc.ByteString

collections.abc.MappingView

collections.abc.KeysView

collections.abc.ItemsView

collections.abc.ValuesView

contextlib.AbstractContextManager

contextlib.AbstractAsyncContextManager

re.Pattern

re.Match

typing.Dict

typing.List

typing.Set

typing.FrozenSet

typing.Tuple

typing.DefaultDict

typing.OrderedDict

typing.ChainMap

typing.Counter

typing.Deque

typing.Pattern

typing.Match

typing.Text

typing.AbstractSet

typing.ByteString

typing.Collection

typing.Container

typing.ItemsView

typing.KeysView

typing.Mapping

typing.MappingView

typing.MutableMapping

typing.MutableSequence

typing.MutableSet

typing.Sequence

typing.ValuesView