Hlavní navigace

Brython aneb použití jazyka Python ve skriptech přímo v prohlížeči

Pavel Tišnovský

Seznámíme se s projektem nazvaným Brython neboli Browser Python. Jedná se o nástroj umožňující běh skriptů naprogramovaných v Pythonu přímo na HTML stránce s tím, že interně je prováděn transpřeklad do JavaScriptu.

Doba čtení: 29 minut

Sdílet

11. Použití metody document.select()

12. Přístup k obsahu stránky a naprogramování jednoduchého zpracování události

13. Pythonní skript uložený ve zvláštním souboru

14. Přidání nových elementů na stránku

15. Elementy vytvořené uvnitř jiných elementů

16. Práce se SVG

17. A je tedy Brython reálně nasaditelný?

18. Odkazy na Internetu

1. Mainstreamové, alternativní a specializované implementace programovacího jazyka Python

Na stránkách Roota a taktéž na serveru Moje Fedora jsme se již několikrát setkali s různými mainstreamovými ale i alternativními implementacemi programovacího jazyka Python. Kromě klasického CPythonu (ať již verze 2 nebo 3) si připomeňme například projekt nazvaný Jython [1] [2], což je (dnes již bohužel poněkud zastaralá) implementace Pythonu určená pro běh ve virtuálním stroji Javy, popř. IronPython určený pro prostředí .NET. Dále jsme se zmínili o RustPythonu, neboli implementaci Pythonu vytvořené (jak název správně napovídá) v programovacím jazyce Rust. Podobným způsobem je implementován i interpret Pythonu v jazyce Go v projektu gpython.

Obrázek 1: Logo programovacího jazyka Jython.

Věnovali jsme se i poměrně neznámému jazyku Coconut. Jedná se o funkcionální programovací jazyk s pattern matchingem, který je navržen takovým způsobem, aby byl kompatibilní s Pythonem, tj. aby skripty vyvinuté v Pythonu byly v Coconutu spustitelné (zpětně ovšem nikoli, protože syntaxe a sémantika Coconutu byla v mnoha ohledech rozšířena). Přesnější informace o tom, se kterými verzemi Pythonu je Coconut kompatibilní, naleznete na adrese http://coconut.readthedoc­s.io/en/master/DOCS.html#com­patible-python-versions. Zapomenout nesmíme ani na MyPy, což je projekt, kterému bude věnován samostatný článek.

Zatímco výše zmíněné nástroje JythonRustPython jsou skutečnými alternativními implementacemi interpretru Pythonu navazujícími na CPython (interpret Pythonu naprogramovaný v céčku), existují i další implementace, které se zaměřují například překlad programů vyvinutých v Pythonu do strojového kódu, a to jak před spuštěním aplikace (AOT – Ahead Of Time compilation) nebo během její činnosti (JIT – Just In Time compilation). Mezi tyto nástroje patří především PyPy (používaný v mnoha projektech) a dále Cython (ne CPython), RPython a Numba, které k problematice překladu skriptů vytvořených v Pythonu přistupují různými (zcela odlišnými) cestami.

RPython používá AOT a striktně omezuje některé vlastnosti jazyka, zatímco Numba a PyPy používá JIT a nabízí programátorům prakticky stejné možnosti jako klasický CPython.

Obrázek 2: Logo projektu Cython.

Obrázek 3: Logo projektu PyPy.

S bližšími informacemi o Cythonu, RPythonu i nástroji Numba jsme se seznámili v následujících článcích:

  1. RPython: překvapivě výkonný dialekt Pythonu, na němž je založen PyPy
    https://www.root.cz/clanky/rpython-prekvapive-vykonny-dialekt-pythonu-na-nemz-je-zalozen-pypy/
  2. RPython vs Cython aneb dvojí přístup k překladu Pythonu do nativního kódu
    https://www.root.cz/clanky/rpython-vs-cython-aneb-dvoji-pristup-k-prekladu-pythonu-do-nativniho-kodu/
  3. Praktické použití nástroje Cython při překladu Pythonu do nativního kódu
    https://www.root.cz/clanky/prakticke-pouziti-nastroje-cython-pri-prekladu-pythonu-do-nativniho-kodu-1/
  4. Projekt Numba aneb další přístup k překladu Pythonu do nativního kódu
    https://www.root.cz/clanky/projekt-numba-aneb-dalsi-pristup-k-prekladu-pythonu-do-nativniho-kodu/

Obrázek 4: Porovnání doby výpočtu Mandelbrotovy množiny RPythonem, Cythonem (bez i s type hinty) a variantou naprogramovanou přímo v ANSI C. Z tohoto grafu je dobře patrné, jak důležité je pro Cython mít k dispozici o typech proměnných, parametrů a návratových kódů funkcí (jinými slovy – provedené optimalizace v tomto případě nezískáme zadarmo).

2. Programovací jazyk Python a webové aplikace

Programovací jazyk Python se v současnosti používá v mnoha aplikačních oblastech – od jednoduchých skriptů umožňujících a zjednodušujících administraci systému přes složitější utility, desktopové aplikace (PyQt, PySide, wxPython, Tkinter, PyGObject či Wax) a webové služby až po zpracování dat, strojové učení (ML – machine learning) a umělou inteligenci (AI – artificial intelligence). Dnes nás ovšem bude zajímat především použití Pythonu při tvorbě webových služeb a webových aplikací. V této oblasti se Python používá především na back endu, tj. pro tu část webové služby/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 samozřejmě není pokryta pouze Pythonem, ale najdeme zde i 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 jazyka byly prozatím neúspěšné (pokusů bylo hned několik, připomeňme například browsery s TCL, VBScript či projekt Dart). Ovšem stále se můžeme setkat se snahami JavaScript nepoužívat přímo, popř. ho obejít jinými nástroji. Příkladem mohou být technologie umožňující tvorbu webových aplikací podobným způsobem, jakoby se jednalo o aplikace desktopové. Příkladem tohoto přístupu mohou být projekty Pyjamas (pro Python), Google Web Toolkit (GWT), Apache Cordova atd.

3. Python ve funkci programovacího jazyka pro front end

Je tedy vůbec možné a praktické použít Python přímo na webovém front endu a pokud to je možné, jakou za to zaplatíme cenu? Ve skutečnosti existuje hned několik projektů, které se více či méně úspěšným způsobem snaží o to, aby byl Python na front endu skutečně použitelný, a to i pro reálně provozované aplikace. Mezi tyto projekty patří například:

  1. Brython, s jehož některými možnostmi se seznámíme dnes ve druhé části článku. Jedná se o transpřekladač z Pythonu do JavaScriptu, přičemž samotný překlad (resp. přesněji řečeno transpřeklad) probíhá na pozadí, což znamená, že přímo v kódu webové stránky je umístěn (či načítán) kód v Pythonu. Podobné řešení jsme již viděli, například u projektu Wisp (jazyk podobný Clojure) či lua.js (transpřeklad z jazyka Lua). Výhodou Brythonu je, že se jakékoli úpravy ihned projeví v aplikaci po znovunačtení stránky (F5).
  2. Transcrypt je taktéž transpřekladačem Pythonu (konkrétně Pythonu 3) do JavaScriptu. Samotný transpřeklad je napsaný velmi dobře – zhruba platí, ž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 atd.)
  3. Podobným způsobem pracuje i projekt nazvaný pyjaco, který naleznete na adrese https://github.com/chrivers/pyjaco.
  4. Skulpt je naproti tomu v mnoha ohledech podobný projektu Brython, protože taktéž umožňuje provádět transpřeklad na pozadí (programátor tedy pracuje pouze se zdrojovým kódem vytvořeným v Pythonu).
  5. Velmi zajímavým nástrojem, který názorně ukazuje, jak vlastně transpřeklad funguje (a že jeho výsledek může být čitelný), je nástroj s poněkud zvláštním jménem fiddlesalad, který naleznete na adrese http://fiddlesalad.com/python/. Tento nástroj umožňuje zápis zdrojového kódu v Pythonu, který je ihned (již v době zápisu) transpřekládán do JavaScriptu a současně i spouštěn.
Poznámka: povšimněte si, že všechny projekty zmíněné v předchozím textu jsou ve skutečnosti transpřekladači neboli transpilery. Jedná se o technologii zajišťující, aby se i ve webovém prohlížeči mohlo (nepřímo) pracovat s dalšími programovacími jazyky, nejenom se všudypřítomným a nativně podporovaným JavaScriptem. Další variantou je interpretace s využitím interpretru psaného v JavaScriptu popř. použití WebAssembly (viz též navazující kapitoly).

Další více či méně zajímavé a užitečné projekty můžete najít na stránce Web Browser Programming in Python, popř. v tabulce umístěné na adrese http://stromberg.dnsalias­.org/~strombrg/pybrowser/pyt­hon-browser.html.

Obrázek 4: Prostředí webového IDE fiddlesalad. Zapsaný zdrojový kód je ihned transpřekládán i spouštěn.

4. JavaScript v roli assembleru pro Web

JavaScript is an assembly language. The JavaScript + HTML generate is like a .NET assembly. The browser can execute it, but no human should really care what's there.
Erik Meijer

Pokud se bavíme o webových aplikacích, samozřejmě nemůžeme nezmínit JavaScript, se všemi jeho přednostmi a zápory. Ovšem nejedná se jen o čistě webové aplikace zobrazované ve webovém prohlížeči, protože JavaScript je používán i v desktopových aplikacích založených například na technologii Electron (příkladem takové aplikace může být Visual Studio Code, které je podle průzkumu StackOverflow nejpopulárnějším IDE roku 2019). Rozšíření JavaScriptu je pochopitelné, protože většina současných webových prohlížečů (samozřejmě pokud se nejedná o specializované prohlížeče typu Lynx) obsahuje interpret a popř. i JIT (just-in-time) překladač JavaScriptu, přičemž podpora pro další programovací jazyky přímo neexistuje. To s sebou přináší některé výhody, ale i mnoho záporů, ostatně jako každá monokultura (nejenom) v IT. Pro webové aplikace, v nichž se intenzivně pracuje především s DOMem HTML stránky, nemusí být toto omezení tak kritické, ovšem pro výpočetně náročnější aplikace popř. ve chvíli, kdy se ve větší míře používá grafika (2D či 3D canvas) je již podpora pouze relativně vysokoúrovňového a dynamicky typovaného (a tím pádem hůře JITovatelného) JavaScriptu někdy poměrně omezující, i když je nutno říci, že se optimalizacemi JITu JavaScriptu věnovalo mnoho práce a výsledky jsou patrné (navíc existuje i podpora pro asm.js, viz další text).

Obrázek 4: Textový editor Atom používá technologii Electron.

Ovšem JavaScript nemusí být vhodným pro všechny typy projektů a pro všechny vývojářské týmy. V relativně nedávné minulosti proto vzniklo a pořád ještě vzniká mnoho projektů, jejichž cílem je umožnit tvorbu webových aplikací pro prohlížeč v jiných programovacích jazycích. Zdrojové kódy je pak nutné nějakým způsobem zpracovat (transpřeložit, přeložit, interpretovat…) takovým způsobem, aby je bylo možné ve webovém prohlížeči spustit. Možností je hned několik – lze použít plugin (velmi problematické a dnes značně nepopulární řešení), využít transpřekladač do JavaScriptu či naprogramovat a spustit virtuální stroj popř. interpret daného jazyka implementovaný opět v JavaScriptu.

Další z možných řešení, které se nabízí, je buď použití nativních klientů (se všemi z toho plynoucími bezpečnostními aj. důsledky, složitější administrací atd.) nebo využití nějaké formy virtuálního stroje, který by ovšem měl být co nejjednodušší a ideálně dobře specifikovaný, aby ho bylo možné relativně snadno implementovat ve všech používaných prohlížečích. V současnosti je tímto virtuálním strojem WebAssembly, což je popis instrukcí tohoto stroje i jeho očekávaného chování. Díky tomu, že je WebAssembly podporován prakticky všemi relevantními prohlížeči, začal se postupně rozšiřovat, zejména ve výpočetně intenzivnějších aplikacích (například se jedná o šachový engine atd.).

Jednu z dnes velmi populárních technik umožňujících použití prakticky libovolného programovacího jazyka pro tvorbu aplikací běžících na straně webového prohlížeče, představuje použití takzvaných transcompilerů (source-to-source compiler) zajišťujících překlad programu napsaného ve zdrojovém programovacím jazyce do funkčně identického programu napsaného v JavaScriptu (někdy se setkáme i s označením transpiler). Transpřekladač se většinou spouští jen jednou na vývojářském počítači, samotní klienti již mají k dispozici JavaScriptový kód. Výhodou tohoto řešení jsou (obecně) menší nároky na klienta – ten nemusí stahovat a interpretovat zbytečně velké množství kódu, protože dostane k dispozici již minifikovaný kód v JavaScriptu.

Poznámka: ve skutečnosti není technologie transpřekladačů žádným způsobem svázána právě s JavaScriptem, protože se používala (a používá) i pro další manipulace se zdrojovými kódy.

Existuje však i druhá možnost, kdy je samotný transpřekladač naprogramován v JavaScriptu a současně je spouštěn přímo ve webovém prohlížeči klientů. Oba přístupy mají své přednosti, ale pochopitelně i nějaké zápory (například tvůrci uzavřených aplikací pravděpodobně budou upřednostňovat první možnost, protože výstupy transcompilerů jsou většinou dosti nečitelné; dokonce by mohla snaha o prozkoumání kódu spadat pod reverse engineering). Druhá možnost je relativně elegantní v tom ohledu, že se z pohledu programátora webové aplikace skutečně jedná o nový programovací jazyk, který je jakoby přímo zpracováván prohlížečem na stejné úrovni jako JavaScript (v praxi se ovšem ukazuje, že separace původního jazyka od JS engignu není tak čistá, jak by se mohlo na první pohled zdát). Příkladem tohoto řešení může být kombinace JavaScriptu a jazyka WISP:

<html>
    <head>
        <title>Jazyk WISP na webové stránce</title>
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
 
        <script src="wisp.min.js" type="application/javascript">
        </script>
 
        <script type="application/wisp">
        (print "část naprogramovaná ve WISPu")
        </script>
 
        <script type="application/javascript">
        console.log("část naprogramovaná v JavaScriptu")
        </script>
 
    </head>
 
    <body>
    </body>
</html>

Povšimněte si, že na jedné stránce můžeme kombinovat oba výše zmíněné jazyky. Integrace jde ovšem ještě dále, protože z jednoho jazyka lze volat funkci deklarovanou v jazyku druhém.

5. Transpilery v nice ovládnuté JavaScriptem

Problematikou takzvaných transpilerů nebo transpřekladačů (transcompilers, source-to-source compilers), o nichž jsme se zmínili v předchozí kapitole, jsme se již na stránkách Rootu zabývali, a to dokonce několikrát. Připomeňme si například projekty ClojureScript (transpřekladač Clojure → JavaScript), lua2js (transpřekladač Lua → opět JavaScript), Wisp (programovací jazyk podobný Clojure, opět překládaný na pozadí do JavaScriptu) i již výše zmíněný transpřekladač Coconut (ten ovšem nemá s JavaScriptem nic společného). Připomeňme si, že transpřekladače jsou nástroje sloužící pro překlad algoritmů zapsaných v nějakém zdrojovém programovacím jazyce do zvoleného cílového jazyka (ovšem nikoli do nativního kódu či bajtkódu, to je totiž role běžných překladačů).

Transpřekladače se v informatice používají již po několik desetiletí; například se stále můžeme setkat s nástroji, které převádí kód z nějakého vyššího programovacího jazyka do Céčka, které je dnes s trochou nadsázky chápáno jako „univerzální assembler“. Asi nejznámějším příkladem staršího použití transpřekladačů je nástroj nazvaný web2c, jenž slouží pro transformaci zdrojových kódů TeXu do céčka. Transpřekladače se stávají velmi populární i pro programátory webových aplikací (proto se o nich dnes bavíme), a to zejména z toho důvodu, že webové prohlížeče nativně podporují většinou pouze JavaScript, který je tak přirozeně cílovým jazykem transpřekladačů (proto se také JavaScriptu někdy říká „assembler pro web“, viz též odkazy na konci článku). A právě této problematice se budeme podrobněji věnovat v navazujících kapitolách v souvislosti s projektem Brython.

Z praxe můžeme uvést například následující projekty založené na transpřekladači:

# Jazyk či transpřekladač Poznámka
1 CoffeeScript přidání syntaktického cukru do JavaScriptu
2 ClojureScript překlad aplikací psaných v Clojure do JavaScriptu
3 TypeScript nadmnožina jazyka JavaScript, přidání datových typů
4 6to5 transpřeklad z ECMAScript 6 (nová varianta JavaScriptu) do starší varianty JavaScriptu
5 Kaffeine rozšíření JavaScriptu o nové vlastnosti
6 RedScript jazyk inspirovaný Ruby
7 GorillaScript další rozšíření JavaScriptu
8 ghcjs transpřekladač pro fanoušky programovacího jazyka Haskell
9 Haxe transpřekladač, mezi jehož cílové jazyka patří i Java a JavaScript
10 Wisp transpřekladač jazyka podobného Clojure, opět do JavaScriptu
11 ScriptSharp transpřekladač z C# do JavaScriptu
12 Dart transpřekladač z jazyka Dart do JavaScriptu
13 COBOL → C transpřekladač OpenCOBOL
14 COBOL → Java transpřekladač P3COBOL
15 lua2js transpřekladač jazyka Lua, opět do JavaScriptu
16 Coconut transpřekladač jazyka Coconut do Pythonu
Poznámka: seznam všech (či alespoň většiny) známých transpřekladačů do JavaScriptu naleznete například na stránce https://github.com/jashke­nas/coffeescript/wiki/List-of-languages-that-compile-to-JS, i když je nutné varovat, že některé projekty (kromě výše zmíněných) jsou v dosti špatném stavu popř. již vůbec nejsou udržovány.

6. Nástroj Emscripten

Další alternativní technologii, která mi osobně přijde velmi zajímavá a v budoucnu možná i přelomová, představují transpřekladače provádějící překlad z bajtkódu či mezikódu do JavaScriptu (vstupem zde tedy není zdrojový kód v nějakém lidsky čitelném programovacím jazyku, ale většinou binárně reprezentovaný výsledek předchozího překladu). Příkladem tohoto typu transpřekladače je především nástroj Emscripten [1] umožňující překlad kódu z libovolného jazyka podporovaného LLVM (Rust, C, C++, Objective C, D, Ada, Fortran atd.) do JavaScriptu. Podívejme se nyní ve stručnosti na všechny základní kroky, které je zapotřebí provést proto, aby se původní zdrojový kód napsaný například v Céčku, mohl nějakým způsobem spustit ve webovém prohlížeči:

  1. Na vstupu celého procesu je program napsaný v céčku
  2. Nejprve je proveden překlad pomocí clang do mezikódu LLVM (LLVM Intermediate Representation)
  3. Následně je zavolán Fastcomp (jádro překladače Emscriptenu) pro překlad mezikódu z předchozího kroku do JavaScriptu
  4. Výsledný JavaScriptový zdrojový kód je možné využít různými způsoby (node.js na serveru, na WWW stránce atd.)
Poznámka: poslední překlad (do JavaScriptu) generuje kód kompatibilní s asm.js, tj. používá se zde cíleně omezená podmnožina konstrukcí JavaScriptu. Více informací o asm.js naleznete například na stránkách https://developer.mozilla.org/en-US/docs/Games/Tools/asm.js a http://asmjs.org/ (původní verze specifikace). Alternativně může být výsledkem i bajtkód pro WebAssembly, který by měl být menší a tím pádem by se měl načíst a inicializovat rychleji, než je tomu v případě asm.js.

Právě projekt Emscripten do značné míry usnadnil další způsob zajištění běhu programů napsaných v různých programovacích jazycích ve webovém prohlížeči. Pokud je totiž možné přeložit jakýkoli program napsaný v jazycích C či C++ do JavaScriptu (samozřejmě za předpokladu, že se vhodným způsobem budou emulovat použité knihovní funkce), proč by nebylo možné do JavaScriptu rovnou přeložit celý virtuální stroj používaný daným programovacím jazykem? Samozřejmě to možné je, a to zejména v těch případech, kdy je překládaný virtuální stroj (alespoň z dnešního pohledu) malý, což je příklad VM pro jazyk Lua, tak i například poněkud většího virtuálního stroje Pythonu (.NET resp. CLR či Java VM už je pochopitelně mnohem těžší oříšek).

Překladem virtuálního stroje do JavaScriptu získáme poměrně mnoho výhod, zejména pak možnost mít přímo v HTML stránkách původní zdrojové kódy (Lua, Python atd.) a nikoli méně či více nečitelný výstup z transpřekladačů. Za tento postup však také zaplatíme, zejména pomalejším během aplikací v porovnání s nativní VM. V praxi se může jednat o výkonnostní propad zhruba na polovinu, což ovšem v mnoha aplikacích vůbec není tak špatný výsledek.

Příkladem takového typu virtuálního stroje je LuaJS. Ovšem dnes se zabýváme Pythonem, pro který taktéž vznikl podobný nástroj. Jmenuje se jednoduše PyPy.js a na stránce http://pypyjs.org/ si můžete sami ověřit, že samotný bootstrap je v případě tohoto projektu dosti pomalý (další problém je, že v některých prohlížečích nelze získat fokus terminálu).

7. Projekt Brython se představuje

Ve druhé části článku se seznámíme s některými možnostmi, které nám projekt Brython nabízí. Bude nás zajímat především to, jak se vlastně Brython vloží do webové aplikace, jak se inicializuje, kam a jakým způsobem se uloží zdrojové kódy front endu psané v Pythonu a v neposlední řadě je nutné se seznámit i se způsobem, jakým Brython pracuje s DOMem webové stránky i se systémem událostí (events). Bez podpory těchto dvou nezbytných částí webové aplikace by použití Brythonu pro běžné projekty prakticky zcela postrádalo význam.

Nejprve získáme všechny potřebné nástroje. Ty jsou dostupné na stránce https://github.com/brython-dev/brython/releases. Stáhneme poslední oficiální verzi Brythonu vydanou doslova před několika dny:

$ wget https://github.com/brython-dev/brython/releases/download/3.8.0/Brython-3.8.0.tar.bz2

Získaný tarball rozbalíme:

$ tar xvfj Brython-3.8.0.tar.bz2 
 
Brython-3.8.0/README.txt
Brython-3.8.0/demo.html
Brython-3.8.0/brython.js
Brython-3.8.0/brython_stdlib.js
Brython-3.8.0/unicode.txt

Po rozbalení je zajímavé se podívat na velikosti jednotlivých souborů, které tvoří transpřekladač Brythonu i jeho základní knihovnu (která se snaží být kompatibilní s Pythonem 2 i 3):

$ ls -l
 
total 4992
-rw-r--r-- 1 tester tester  707388 říj 15 12:16 brython.js
-rw-r--r-- 1 tester tester 3561739 říj 15 12:16 brython_stdlib.js
-rw-r--r-- 1 tester tester   40741 říj 15 12:16 demo.html
-rw-r--r-- 1 tester tester     324 říj 15 08:40 README.txt
-rw-r--r-- 1 tester tester     386 bře 29  2019 test.html
-rw-r--r-- 1 tester tester  787651 říj 15 12:16 unicode.txt

I když jsou oba soubory brython.jsbrython_stdlib.js minifikovány, je jejich velikost značná, protože si musíme uvědomit, že oba soubory budou muset být (alespoň poprvé) přeneseny na klienta a tam následně interpretovány. To může mnohdy podstatným způsobem prodloužit spuštění aplikace na straně klienta, přičemž rychlost (či spíše pomalost) spuštění do značné míry závisí na rychlosti přenosu dat a taktéž na kvalitě a rychlosti interpretru a JITu JavaScriptu. Z tohoto důvodu není vhodné Brython používat například na úvodních stránkách společností atd. (na druhou stranu je ovšem samotný běh skriptů srovnatelný s JavaScriptem, takže se u rozsáhlejších podnikových aplikací může pomalost prvního spuštění akceptovat).

V Brythonu je možné použít tyto základní funkce a třídy (bez nutnosti jejich explicitního importu):

abs, all, any, ascii, bin, bool, bytes, callable, chr, classmethod, delattr,
dict, dir, divmod, enumerate, eval, exec, filter, float, frozenset, getattr,
globals, hasattr, hash, hex, id, input, int, isinstance, iter, len, list,
locals, map, max, memoryview, min, next, object, open, ord, pow, print,
property, range, repr, reversed, round, set, setattr, slice, sorted, str, sum,
super, tuple, type, vars, zip, __import__
Poznámka: pro instalaci je možné použít i pip nebo pip3:
$ pip3 install brython

popř.:

$ pip3 install --user brython

8. Stránka s demonstračními příklady

Po rozbalení všech souborů si můžeme v prohlížeči nechat zobrazit stránku demo.html s následujícím výsledkem:

Obrázek 5: Stránka demo.html zobrazená ve webovém prohlížeči s povoleným JavaScriptem.

Poznámka: zejména na méně výkonných počítačích je patrné, že inicializace transpřekladače Brythonu i jeho ekosystému (základní knihovny atd.) není okamžitá – celá stránka se mnohdy zobrazí až po několika sekundách. Jedná se o zdržení, které v tomto případě není způsobeno pomalým přenosem dat, ale „pouze“ interpretací obou souborů brython.jsbrython_stdlib.js společně se skripty uložené přímo do stránky demo.html.

9. Python na webové stránce

Nyní se podívejme na zcela základní způsob použití skriptů na webové stránce. V následujícím příkladu zavoláme funkci document.write, která vypíše text přímo do plocho stránky. V případě JavaScriptu je tato úloha triviální:

<html>
    <head>
        <title>Hello world in JavaScript</title>
    </head>
    <body>
        <script type="application/javascript">
        document.write('Hello world!')
        </script>
    </body>
</html>

Pokud ovšem budeme chtít použít Python tranpřekládaný Brythonem, je nutné implementovat více kroků. Nejdříve je nutné, ideálně v hlavičce HTML stránky, načíst výše zmíněný soubor brython.js:

<script src="brython.js"></script>
Poznámka: klidně můžete explicitně uvést i MIME typ tohoto souboru.

Dále je nutné zajistit inicializaci transpřekladače, například v události typu onload:

<body onload="brython()">
...
...
...

Nyní přichází ta nejzajímavější část – samotný zdrojový kód, nyní již naprogramovaný přímo v Pythonu:

<script type="text/python">
from browser import document
 
document.write('Hello world!')
</script>

Celá stránka s inicializací Brythonu i se zdrojovým kódem napsaným v Pythonu může vypadat takto:

<html>
    <head>
        <title>Hello world in Python</title>
        <script src="brython.js"></script>
    </head>
    <body onload="brython()">
        <script type="text/python">
        from browser import document
 
        document.write('Hello world!')
        </script>
    </body>
</html>

10. Základní přístup k DOMu stránky

Ze skriptu napsaného v Pythonu lze přistupovat k DOMu stránky. Následující příklad ukazuje, jakým způsobem je možné změnit text nadpisu (či jiného elementu), jehož ID je nastaveno na „nadpis“:

<html>
    <head>
        <title>Hello world #2 in Python</title>
        <script src="brython.js"></script>
    </head>
    <body onload="brython()">
        <h1 id='nadpis'></h1>
        <script type="text/python">
        from browser import document
 
        document.getElementById('nadpis').text = 'Hello world'
        </script>
    </body>
</html>

Existuje ovšem i kratší způsob se stejným výsledkem:

<html>
    <head>
        <title>Hello world #2 in Python</title>
        <script src="brython.js"></script>
    </head>
    <body onload="brython()">
        <h1 id='nadpis'></h1>
        <script type="text/python">
        from browser import document
 
        document['nadpis'].text = 'Hello world'
        </script>
    </body>
</html>

11. Použití metody document.select()

Elementy na stránce lze vybírat i dalšími způsoby, nejenom pomocí jejich ID. K výběru slouží metoda document.select(), které lze předat řetězec, z jehož tvaru je odvozen příslušný typ selektoru:

Zápis Význam
document.select(‚.cls‘) elementy, jejichž třída je nastavena na „cls“
document.select(‚div‘) elementy daného typu
document.select(‚H1.cls‘) elementy daného typu, jejichž třída je nastavena na „cls“
document.select(‚#id‘) elementy se zvoleným ID (jako v předchozí kapitole)
document.select(‚a[title]‘) elementy obsahující zadaný atribut

Alternativní způsob výběru elementu pomocí jeho ID lze tedy provést i následujícím způsobem:

<html>
    <head>
        <title>Hello world #2 in Python</title>
        <script src="brython.js"></script>
    </head>
    <body onload="brython()">
        <h1 id='nadpis'></h1>
        <script type="text/python">
        from browser import document
 
        document.select('#nadpis')[0].text = 'Hello world'
        </script>
    </body>
</html>
Poznámka: povšimněte si, že je nutné získat první vrácený element, i když by teoreticky měl existovat jen jediný element s unikátním ID.

V dalším příkladu je vybrán element typu H1, jehož třída je nastavena na „nadpis“:

<html>
    <head>
        <title>Hello world #2 in Python</title>
        <script src="brython.js"></script>
    </head>
    <body onload="brython()">
        <h1 class='nadpis'></h1>
        <script type="text/python">
        from browser import document
 
        document.select('h1.nadpis')[0].text = 'Hello world'
        </script>
    </body>
</html>

12. Přístup k obsahu stránky a naprogramování jednoduchého zpracování události

Při tvorbě interaktivních webových aplikací je nutné reagovat na různé typy událostí. Pro registraci události (na nějaký handler) se používá metoda bind:

document["button1"].bind("click", echo)

Tento zápis zaregistruje událost typu „click“ (tedy kliknutí levým tlačítkem myši) pro tlačítko s identifikátorem „button1“. Pokud k události dojde, zavolá se funkce echo naprogramovaná přímo v Pythonu. Tato funkce vypíše do dialogu obsah vstupního textového pole s identifikátorem „zone“):

def echo(ev):
    alert(document["zone"].value)

Celý příklad (inspirovaný příkladem na stránce Brythonu) vypadá následovně:

<html>
<head>
<script src="brython.js"></script>
</head>
<body onload="brython()">
<script type="text/python">
from browser import document, alert
 
# bind event 'click' on button to function echo
 
def echo(ev):
    alert(document["zone"].value)
 
document["button1"].bind("click", echo)
alert("loaded")
</script>
<input id="zone">
<button id="button1">click !</button>
</body>
</html>

13. Pythonní skript uložený ve zvláštním souboru

Kombinace Pythonu přímo s HTML kódem stránky není většinou nejlepším řešením pro jakékoli skripty delší než několik řádků. Brython umožňuje skript uložit do zvláštního souboru a načíst ho běžným způsobem – přes značku script. Nejprve si ukažme, jak se toto rozdělení provede a až poté si popíšeme způsob spuštění takové stránky. Samotná HTML stránka se změní následovně:

<html>
    <head>
        <title>Hello world #3 in Python</title>
        <script src="brython.js"></script>
    </head>
    <body onload="brython()">
        <h1 class='nadpis'></h1>
        <script type="text/python" src="hello_world.py" />
    </body>
</html>
Povšimněte si, že se zde pouze odkazujeme na skript, který ovšem již není součástí souboru s HTML stránkou.

Skript „hello_world.py“ je již kompletně napsaný v Pythonu a bude tedy korektně zobrazen i barevně zvýrazněn v prakticky jakémkoli moderním programátorském textovém editoru:

from browser import document
 
document.select('h1.nadpis')[0].text = 'Hello world'

Problém ovšem nastane při zobrazení stránky, protože webový prohlížeč většinou odmítne načtení externího skriptu kvůli mechanismu CORS (což je jen dobře, že k tomuto odmítnutí dojde). Řešení je jednoduché – spustíme si vlastní HTTP server, který je dodáván přímo v základní instalaci CPythonu (verze 2 i verze 3). Následující příkaz je nutné spustit v adresáři, kde se nachází jak kód HTML stránky, tak i Pythonní skript:

$ python3 -m http.server
 
Serving HTTP on 0.0.0.0 port 8000 ...
127.0.0.1 - - [23/Oct/2019 20:50:34] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [23/Oct/2019 20:50:34] code 404, message File not found
127.0.0.1 - - [23/Oct/2019 20:50:34] "GET /favicon.ico HTTP/1.1" 404 -
127.0.0.1 - - [23/Oct/2019 20:50:37] "GET /test3.html HTTP/1.1" 200 -
127.0.0.1 - - [23/Oct/2019 20:50:37] "GET /brython.js HTTP/1.1" 200 -
127.0.0.1 - - [23/Oct/2019 20:50:37] "GET /test.py?1571856637812 HTTP/1.1" 200 -
Poznámka: pochopitelně je možné použít i klasické httpd s tím, že se HTML stránka i všechny další potřebné soubory uloží do adresáře /var/www/ (záleží pochopitelně na konkrétním nastavení httpd).

14. Přidání nových elementů na stránku

Do HTML stránky lze přidat nové elementy s využitím přetíženého operátoru <=. Nové elementy se vytváří pomocí konstant definovaných v modulu browser.html, přičemž je nutné mít na paměti, že jména elementů se zapisují velkými písmeny. Podívejme se opět na jednoduchý příklad typu „Hello world“, tentokrát ovšem implementovaný zcela odlišným způsobem:

<html>
    <head>
        <title>Hello world #4 in Python</title>
        <script src="brython.js"></script>
    </head>
    <body onload="brython()">
        <script type="text/python">
from browser import document
from browser import html
 
document <= html.H1("Hello world!")
        </script>
    </body>
</html>

15. Elementy vytvořené uvnitř jiných elementů

Brython podporuje jeden pěkný trik – vytvoření elementů vnořených do jiných elementů. Tohoto způsobu můžeme využít například pro vytvoření číslovaného seznamu či seznamu s odrážkami:

<html>
    <head>
        <title>Hello world #3 in Python</title>
        <script src="brython.js"></script>
    </head>
    <body onload="brython()">
        <h1 class='nadpis'></h1>
        <script type="text/python">
from browser import document
from browser import html
 
document <= html.UL(html.LI('item %s' %i) for i in range(1,6))
        </script>
    </body>
</html>

16. Práce se SVG

Do HTML stránky je možné vložit vektorový obrázek SVG a manipulovat s ním pomocí Brythonu. Pokud je například na stránce vytvořen prázdný SVG obsahující plochu s ID nastavenou na „drawing“, můžeme provést vykreslení vektorového obrázku:

from browser import document
from browser import svg
 
title = svg.text('Title', x=70, y=25, font_size=22,
                 text_anchor="middle")
 
circle = svg.circle(cx=70, cy=120, r=40,
                    stroke="black",stroke_width="2",fill="red")

Tyto dva elementy se přidají do kresby takto:

drawing = document['drawing']
drawing <= title
drawing <= circle

Samotný SVG může být skutečně prázdný:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256" >
    <g id="drawing">
    </g>
</svg>

17. A je tedy Brython reálně nasaditelný?

Vážený čtenář si pochopitelně (a to zcela oprávněně) může položit otázku, jestli je Brython v současném stavu vůbec reálně použitelným projektem. V dnešní podobě (verze 3.8.0) se jedná o stabilní řešení a samotné zpracování skriptů může být pro běžné projekty dostatečně rychlé (ostatně například při manipulaci s DOMem více záleží na rychlosti renderovacího engine prohlížeče a nikoli interpretru jazyka). Ovšem musíme se zmínit i o některých nevýhodách. Zejména je nutné počítat s tím, že webový prohlížeč bude muset stáhnout celý (i když minifikovaný) zdrojový soubor s transpřekladačem Pythonu i jeho základní knihovny. Jádro problému spočívá ve velikosti tohoto souboru, která sice nemusí vadit u větších vnitrofiremních aplikací (založených například na konceptu OPA), ovšem na druhou stranu se nejedná o ten nejlepší nápad použít Brython například přímo na úvodní stránce firmy/projektu dostupné na internetu – vliv pomalého připojení je zde patrný, což si ostatně můžete odzkoušet například použitím nástroje netem.

Komplikace mohou nastat i ve chvíli, kdy se webová aplikace netvoří na zelené louce, ale provádí se úpravy existující aplikace naprogramované typicky v JavaScriptu nebo v TypeScriptu (s jazykem CoffeeScript se již setkávám méně často, ještě méně pak s Dartem, což je zvláštní, protože před několika lety se právě o těchto dvou jazycích vedly dlouhé diskuze, vznikala o nich spousta článků, příspěvků na konferencích atd.). Taktéž je nutné počítat s tím, že při použití Brythonu nejsou k dispozici žádné rozsáhlé a populární frameworky typu Angular či React, takže zde již skutečně záleží na konkrétních požadavcích projektu a taktéž na složení vývojového týmu popř. dostupnosti dalších front endových vývojářů.

Pokud vám projekt Brython z nějakého (například výše uvedeného) důvodu nevyhovuje, ale stále preferujete použití Pythonu i na front endu, je možné vyzkoušet některý alternativní projekt, který provádí transpřeklad na počítači vývojáře (či ještě lépe na CI/CD) a nikoli až v prohlížeči uživatele. Nejznámější alternativou je již výše zmíněný Transcrypt popř. Skulpt.

18. Odkazy na Internetu

  1. Ahead-of-time compilation
    https://en.wikipedia.org/wiki/Ahead-of-time_compilation
  2. Just-in-time compilation
    https://en.wikipedia.org/wiki/Just-in-time_compilation
  3. A quick guide about Python implementations
    https://blog.rmotr.com/a-quick-guide-about-python-implementations-aa224109f321
  4. mypy
    http://www.mypy-lang.org/
  5. RPython Language
    https://rpython.readthedoc­s.io/en/latest/rpython.html
  6. Numba
    http://numba.pydata.org/
  7. How Brython works
    https://github.com/brython-dev/brython/wiki/How%20Brython%20works
  8. Brython – A Python 3 implementation for client-side web programming
    http://www.brython.info/
  9. Brython videos and talks
    https://github.com/brython-dev/brython/wiki/Brython-videos-and-talks
  10. Python in browser (tabulka s porovnáními)
    http://stromberg.dnsalias­.org/~strombrg/pybrowser/pyt­hon-browser.html
  11. Coconut: Simple, elegant, Pythonic functional programming
    http://coconut-lang.org/
  12. coconut 1.1.0 (Python package index)
    https://pypi.python.org/py­pi/coconut/1.1.0
  13. Coconut Tutorial
    http://coconut.readthedoc­s.io/en/master/HELP.html
  14. Coconut FAQ
    http://coconut.readthedoc­s.io/en/master/FAQ.html
  15. Coconut Documentation
    http://coconut.readthedoc­s.io/en/master/DOCS.html
  16. Coconut na Redditu
    https://www.reddit.com/r/Pyt­hon/comments/4owzu7/coconut_fun­ctional_programming_in_pyt­hon/
  17. Repositář na GitHubu
    https://github.com/evhub/coconut
  18. patterns
    https://github.com/Suor/patterns
  19. Source-to-source compiler
    https://en.wikipedia.org/wiki/Source-to-source_compiler
  20. The Lua VM, on the Web
    https://kripken.github.io/lu­a.vm.js/lua.vm.js.html
  21. Lua.vm.js REPL
    https://kripken.github.io/lu­a.vm.js/repl.html
  22. lua2js
    https://www.npmjs.com/package/lua2js
  23. JavaScript is Assembly Language for the Web: Sematic Markup is Dead! Clean vs. Machine-coded HTML
    http://www.hanselman.com/blog/Ja­vaScriptIsAssemblyLanguage­ForTheWebSematicMarkupIsDe­adCleanVsMachinecodedHTML­.aspx
  24. JavaScript is Web Assembly Language and that's OK.
    http://www.hanselman.com/blog/Ja­vaScriptIsWebAssemblyLangu­ageAndThatsOK.aspx
  25. Dart
    https://www.dartlang.org/
  26. CoffeeScript
    http://coffeescript.org/
  27. TypeScript
    http://www.typescriptlang.org/
  28. JavaScript: The Web Assembly Language?
    http://www.informit.com/ar­ticles/article.aspx?p=1856657
  29. asm.js
    http://asmjs.org/
  30. List of languages that compile to JS
    https://github.com/jashke­nas/coffeescript/wiki/List-of-languages-that-compile-to-JS
  31. WebAssembly
    https://webassembly.org/
  32. WebAssembly na Wiki Golangu
    https://github.com/golang/go/wi­ki/WebAssembly
  33. The future of WebAssembly – A look at upcoming features and proposals
    https://blog.scottlogic.com/2018/07/20/wasm-future.html
  34. Writing WebAssembly By Hand
    https://blog.scottlogic.com/2018/04/26/we­bassembly-by-hand.html
  35. WebAssembly Specification
    https://webassembly.github­.io/spec/core/index.html
  36. Index of Instructions
    https://webassembly.github­.io/spec/core/appendix/in­dex-instructions.html
  37. The WebAssembly Binary Toolkit
    https://github.com/WebAssembly/wabt
  38. Will WebAssembly replace JavaScript? Or Will WASM Make JavaScript More Valuable in Future?
    https://dev.to/vaibhavshah/will-webassembly-replace-javascript-or-will-wasm-make-javascript-more-valuable-in-future-5c6e
  39. Roadmap (pro WebAssemly)
    https://webassembly.org/roadmap/
  40. Podpora canvasu ve webových prohlížečích
    https://caniuse.com/#feat=canvas
  41. Writing Web Applications (se zaměřením na jazyk Go)
    https://golang.org/doc/articles/wiki/
  42. Golang Web Apps
    https://www.reinbach.com/blog/golang-webapps-1/
  43. Python in Browser: How to choose between Brython, PyPy.js, Skulpt and Transcrypt?
    https://stackoverflow.com/qu­estions/30155551/python-in-browser-how-to-choose-between-brython-pypy-js-skulpt-and-transcrypt
  44. Google web toolkit
    http://www.gwtproject.org/
  45. Transcrypt
    https://transcrypt.org/
  46. Skulpt: Python. Client Side.
    http://skulpt.org/
  47. Web Browser Programming in Python
    https://wiki.python.org/mo­in/WebBrowserProgramming
  48. RPython Frontend and C Wrapper Generator
    http://www.codeforge.com/ar­ticle/383293
  49. PyPy’s Approach to Virtual Machine Construction
    https://bitbucket.org/pypy/ex­tradoc/raw/tip/talk/dls2006/py­py-vm-construction.pdf
  50. Tutorial: Writing an Interpreter with PyPy, Part 1
    https://morepypy.blogspot­.com/2011/04/tutorial-writing-interpreter-with-pypy.html
  51. A simple interpreter from scratch in Python (part 1)
    http://www.jayconrod.com/posts/37/a-simple-interpreter-from-scratch-in-python-part-1
  52. Python 2.7 will retire in…
    https://pythonclock.org/
  53. PyPy (home page)
    https://pypy.org/
  54. PyPy (dokumentace)
    http://doc.pypy.org/en/latest/
  55. Dart
    https://dart.dev/
  56. VBScript
    https://en.wikipedia.org/wi­ki/VBScript
  57. Minification (programming)
    https://en.wikipedia.org/wi­ki/Minification_(programmin­g)
  58. netem
    https://wiki.linuxfoundati­on.org/networking/netem