Obsah
1. Mainstreamové, alternativní a specializované implementace programovacího jazyka Python
2. Programovací jazyk Python a webové aplikace
3. Python ve funkci programovacího jazyka pro front end
4. JavaScript v roli assembleru pro Web
5. Transpilery v nice ovládnuté JavaScriptem
7. Projekt Brython se představuje
8. Stránka s demonstračními příklady
10. Základní přístup k DOMu stránky
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ů
17. A je tedy Brython reálně nasaditelný?
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.readthedocs.io/en/master/DOCS.html#compatible-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 Jython i RustPython 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:
- 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/ - 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/ - 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/ - 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:
- 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).
- 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.)
- Podobným způsobem pracuje i projekt nazvaný pyjaco, který naleznete na adrese https://github.com/chrivers/pyjaco.
- 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).
- 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.
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/python-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.
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 |
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:
- Na vstupu celého procesu je program napsaný v céčku
- Nejprve je proveden překlad pomocí clang do mezikódu LLVM (LLVM Intermediate Representation)
- Následně je zavolán Fastcomp (jádro překladače Emscriptenu) pro překlad mezikódu z předchozího kroku do JavaScriptu
- 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.)
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.js i brython_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__
$ 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.
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>
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>
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>
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 -
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
- Ahead-of-time compilation
https://en.wikipedia.org/wiki/Ahead-of-time_compilation - Just-in-time compilation
https://en.wikipedia.org/wiki/Just-in-time_compilation - A quick guide about Python implementations
https://blog.rmotr.com/a-quick-guide-about-python-implementations-aa224109f321 - mypy
http://www.mypy-lang.org/ - RPython Language
https://rpython.readthedocs.io/en/latest/rpython.html - Numba
http://numba.pydata.org/ - How Brython works
https://github.com/brython-dev/brython/wiki/How%20Brython%20works - Brython – A Python 3 implementation for client-side web programming
http://www.brython.info/ - Brython videos and talks
https://github.com/brython-dev/brython/wiki/Brython-videos-and-talks - Python in browser (tabulka s porovnáními)
http://stromberg.dnsalias.org/~strombrg/pybrowser/python-browser.html - Coconut: Simple, elegant, Pythonic functional programming
http://coconut-lang.org/ - coconut 1.1.0 (Python package index)
https://pypi.python.org/pypi/coconut/1.1.0 - Coconut Tutorial
http://coconut.readthedocs.io/en/master/HELP.html - Coconut FAQ
http://coconut.readthedocs.io/en/master/FAQ.html - Coconut Documentation
http://coconut.readthedocs.io/en/master/DOCS.html - Coconut na Redditu
https://www.reddit.com/r/Python/comments/4owzu7/coconut_functional_programming_in_python/ - Repositář na GitHubu
https://github.com/evhub/coconut - patterns
https://github.com/Suor/patterns - Source-to-source compiler
https://en.wikipedia.org/wiki/Source-to-source_compiler - The Lua VM, on the Web
https://kripken.github.io/lua.vm.js/lua.vm.js.html - Lua.vm.js REPL
https://kripken.github.io/lua.vm.js/repl.html - lua2js
https://www.npmjs.com/package/lua2js - JavaScript is Assembly Language for the Web: Sematic Markup is Dead! Clean vs. Machine-coded HTML
http://www.hanselman.com/blog/JavaScriptIsAssemblyLanguageForTheWebSematicMarkupIsDeadCleanVsMachinecodedHTML.aspx - JavaScript is Web Assembly Language and that's OK.
http://www.hanselman.com/blog/JavaScriptIsWebAssemblyLanguageAndThatsOK.aspx - Dart
https://www.dartlang.org/ - CoffeeScript
http://coffeescript.org/ - TypeScript
http://www.typescriptlang.org/ - JavaScript: The Web Assembly Language?
http://www.informit.com/articles/article.aspx?p=1856657 - asm.js
http://asmjs.org/ - List of languages that compile to JS
https://github.com/jashkenas/coffeescript/wiki/List-of-languages-that-compile-to-JS - WebAssembly
https://webassembly.org/ - WebAssembly na Wiki Golangu
https://github.com/golang/go/wiki/WebAssembly - The future of WebAssembly – A look at upcoming features and proposals
https://blog.scottlogic.com/2018/07/20/wasm-future.html - Writing WebAssembly By Hand
https://blog.scottlogic.com/2018/04/26/webassembly-by-hand.html - WebAssembly Specification
https://webassembly.github.io/spec/core/index.html - Index of Instructions
https://webassembly.github.io/spec/core/appendix/index-instructions.html - The WebAssembly Binary Toolkit
https://github.com/WebAssembly/wabt - 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 - Roadmap (pro WebAssemly)
https://webassembly.org/roadmap/ - Podpora canvasu ve webových prohlížečích
https://caniuse.com/#feat=canvas - Writing Web Applications (se zaměřením na jazyk Go)
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Python in Browser: How to choose between Brython, PyPy.js, Skulpt and Transcrypt?
https://stackoverflow.com/questions/30155551/python-in-browser-how-to-choose-between-brython-pypy-js-skulpt-and-transcrypt - Google web toolkit
http://www.gwtproject.org/ - Transcrypt
https://transcrypt.org/ - Skulpt: Python. Client Side.
http://skulpt.org/ - Web Browser Programming in Python
https://wiki.python.org/moin/WebBrowserProgramming - RPython Frontend and C Wrapper Generator
http://www.codeforge.com/article/383293 - PyPy’s Approach to Virtual Machine Construction
https://bitbucket.org/pypy/extradoc/raw/tip/talk/dls2006/pypy-vm-construction.pdf - Tutorial: Writing an Interpreter with PyPy, Part 1
https://morepypy.blogspot.com/2011/04/tutorial-writing-interpreter-with-pypy.html - A simple interpreter from scratch in Python (part 1)
http://www.jayconrod.com/posts/37/a-simple-interpreter-from-scratch-in-python-part-1 - Python 2.7 will retire in…
https://pythonclock.org/ - PyPy (home page)
https://pypy.org/ - PyPy (dokumentace)
http://doc.pypy.org/en/latest/ - Dart
https://dart.dev/ - VBScript
https://en.wikipedia.org/wiki/VBScript - Minification (programming)
https://en.wikipedia.org/wiki/Minification_(programming) - netem
https://wiki.linuxfoundation.org/networking/netem