Obsah
1. Transcrypt: další technologie umožňující použití Pythonu na front endu
2. Programovací jazyk Python a front end webových aplikací
3. Programovací jazyk Python a front end webových aplikací
4. Instalace Transcryptu nástrojem pip
5. Instalace v případě použití PDM
7. Instalace JDK pro Google Closure Compiler
8. Transpřeklad Pythonu do JavaScriptu
9. Překlad kódu, který manipuluje se seznamy, do JavaScriptu
10. Překlad kódu, který manipuluje se slovníky, do JavaScriptu
11. Transformace jednoduchých funkcí do JavaScriptu
12. Překlad rekurzivní funkce a taktéž generátoru range
13. Překlad uzávěru z Pythonu do JavaScriptu
14. Funkce s pojmenovanými parametry
16. Vykreslování na canvas (kreslicí plátno) na HTML stránce
18. Cesta (path) na kreslicím plátnu
19. Repositář s demonstračními příklady
1. Transcrypt: další technologie umožňující použití Pythonu na front endu
V dnešním článku se seznámíme s nástrojem Transcrypt. Jedná se o překladač (přesněji řečeno transpřekladač – transpiler) zdrojových kódů z Pythonu do JavaScriptu. Navíc tento nástroj nabízí i celou řadu funkcí ze standardní knihovny Pythonu; tyto funkce je možné v transpřeloženém programu přímo použít. Vzhledem k tomu, že se Transcrypt bude primárně používat pro front end (webové aplikace), nabízí i podporu pro přístup k DOM (Document Object Model) HTML stránky, takže je možné nejenom reagovat na vzniklé události (kliknutí tlačítkem myši na ovládací prvek atd.), ale například i provádět vykreslování na kreslicí plátno (canvas) atd.
2. Programovací jazyk Python a front end webových aplikací
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).
V dnešním článku 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 (i když není problém využít například i Rust či další jazyky).
Zatímco pozice Pythonu v oblasti back endu je poměrně zřejmá, je situace na front endu (tedy v současnosti na straně webového prohlížeče) 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 nativní podporou programovacích jazyků 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říklady tohoto přístupu mohou být projekty Pyjamas (pro Python), Google Web Toolkit (GWT), Apache Cordova atd. (což jsou v současnosti většinou již nepodporované projekty).
3. Programovací jazyk Python a front end webových aplikací
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, což je 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), nevýhodou celková pomalost inicializace webové aplikace.
- 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.). Tímto projektem se budeme zabývat v navazujících kapitolách.
- 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).
- PyScript je oproti předchozím nástrojům realizován odlišně, protože je postaven na projektu nazvaném Pyodide. Jedná se v prvé řadě o upravený překlad celého standardního Pythonu (konkrétně Pythonu, resp. přesněji řečeno CPythonu 3.9), ovšem nikoli do nativního kódu spustitelného přímo z příkazové řádky, ale do bajtkódu WebAssembly. To mj. znamená, že interpret Pythonu, resp. přesněji řečeno programů napsaných pro Python, lze spustit přímo z webového prohlížeče, a to dokonce bez nutnosti mít Python lokálně nainstalovaný – musíme mít pouze k dispozici vhodný webový server (pro jednoduché projekty dokonce ani to ne – stačí lokálně uložené soubory), stránky na github.io atd. PyScript do tohoto ekosystému přidává podporu pro nové HTML značky, zejména <py-script> a <py-env>, jenž umožňují snadný zápis skriptu a navíc i specifikaci cest, modulů a knihoven, které budou na stránce použity.
- 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.
4. Instalace Transcryptu nástrojem pip
K dispozici je hned několik možností instalace Transcryptu. Vzhledem k tomu, že je tento nástroj dostupný přes PyPi, můžeme pro jeho instalaci použít standardní mechanismus dostupný přes pip, resp. pip3. Instalace pouze pro přihlášeného uživatele (nebo do virtuálního prostředí) je snadná:
$ pip3 install --user transcrypt Collecting transcrypt Downloading Transcrypt-3.9.1-py2.py3-none-any.whl (19.0 MB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 19.0/19.0 MB 5.1 MB/s eta 0:00:00 Collecting mypy Downloading mypy-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.1 MB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.1/12.1 MB 5.9 MB/s eta 0:00:00 Collecting typing-extensions>=4.1.0 Downloading typing_extensions-4.8.0-py3-none-any.whl (31 kB) Collecting mypy-extensions>=1.0.0 Downloading mypy_extensions-1.0.0-py3-none-any.whl (4.7 kB) Installing collected packages: typing-extensions, mypy-extensions, mypy, transcrypt Successfully installed mypy-1.6.1 mypy-extensions-1.0.0 transcrypt-3.9.1 typing-extensions-4.8.0
Po instalaci si ověříme, zda je dostupný příkaz transcrypt:
$ transcrypt Transcrypt (TM) Python to JavaScript Small Sane Subset Transpiler Version 3.9.0 Copyright (C) Geatec Engineering. License: Apache 2.0 Usage: transcrypt [-h] [-a] [-am] [-b] [-c] [-d] [-da] [-dc] [-de] [-dl] [-dm] [-dn] [-ds] [-dt] [-e [esv]] [-ec] [-f] [-g] [-i] [-jc] [-jk] [-jm] [-k] [-kc] [-l] [-m] [-n] [-o] [-od outdir] [-p [parent]] [-r] [-s [symbols]] [-sf] [-t] [-u [unit]] [-v] [-x x] [-xr] [-xg] [-xp [xpath]] [-xt] [-*] [source]
5. Instalace v případě použití PDM
Transcrypt lze nastavit i jako závislý balíček při použití nástroje PDM, který byl na Rootu popsán minulý týden. Ukažme si pro úplnost, jak by mohl vypadat projekt, který je na Transcryptu postaven.
Nejprve si necháme vytvořit kostru nového projektu:
$ pdm init
Poctivě odpovíme na položené otázky (většinou jen potvrzením klávesou Enter):
Creating a pyproject.toml for PDM... Please enter the Python interpreter to use 0. /usr/bin/python (3.11) 1. /usr/bin/python3.11 (3.11) 2. /usr/bin/python3 (3.11) Please select (0): 0 Would you like to create a virtualenv with /usr/bin/python? [y/n] (y): Enter Virtualenv is created successfully at /home/ptisnovs/test1/.venv Is the project a library that is installable? If yes, we will need to ask a few more questions to include the project name and build backend [y/n] (n): Enter License(SPDX name) (MIT): Enter Author name (): Enter Author email (): Enter Python requires('*' to allow any) (>=3.11): Enter Project is initialized successfully
Do projektu přidáme závislost na Transcriptu. Výsledný projekt není běžným Pythonovským projektem, kde by výsledkem měla být aplikace nebo knihovna, takže je vlastně jedno, zda použijeme přímou závislost či závislost vývojářskou:
$ pdm add transcrypt
V tomto kroku by se měly nainstalovat stejné balíčky, jako při instalaci přes pip:
Adding packages to default dependencies: transcrypt ? Lock successful Changes are written to pyproject.toml. Synchronizing working set with resolved packages: 4 to add, 0 to update, 0 to remove ✔ Install mypy-extensions 1.0.0 successful ✔ Install typing-extensions 4.8.0 successful ✔ Install transcrypt 3.9.1 successful ✔ Install mypy 1.6.1 successful ? All complete!
Výsledný projektový soubor bude vypadat takto:
[project] name = "" version = "" description = "" authors = [ {name = "", email = ""}, ] dependencies = [ "transcrypt>=3.9.1", ] requires-python = ">=3.11" readme = "README.md" license = {text = "MIT"}
V případě, že zvolíme závislost pro vývojáře, bude soubor nepatrně odlišný:
[project] name = "" version = "" description = "" authors = [ {name = "", email = ""}, ] [tool.pdm.dev-dependencies] dev = [ "transcrypt>=3.9.1", ] requires-python = ">=3.11" readme = "README.md" license = {text = "MIT"}
Pro naprostou úplnost – takto bude vypadat lock file:
# This file is @generated by PDM. # It is not intended for manual editing. [metadata] groups = ["default"] cross_platform = true static_urls = false lock_version = "4.3" content_hash = "sha256:80f8c67207f7ff039345d61bf38429c99a43845a0e7f3c5a710ac5fb657c23dd" [[package]] name = "asyncio" version = "3.4.3" summary = "reference implementation of PEP 3156" files = [ {file = "asyncio-3.4.3-py3-none-any.whl", hash = "sha256:c4d18b22701821de07bd6aea8b53d21449ec0ec5680645e5317062ea21817d2d"}, {file = "asyncio-3.4.3.tar.gz", hash = "sha256:83360ff8bc97980e4ff25c964c7bd3923d333d177aa4f7fb736b019f26c7cb41"}, ] [[package]] name = "mypy" version = "1.6.1" requires_python = ">=3.8" summary = "Optional static typing for Python" dependencies = [ "mypy-extensions>=1.0.0", "typing-extensions>=4.1.0", ] files = [ {file = "mypy-1.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81af8adaa5e3099469e7623436881eff6b3b06db5ef75e6f5b6d4871263547e5"}, {file = "mypy-1.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8c223fa57cb154c7eab5156856c231c3f5eace1e0bed9b32a24696b7ba3c3245"}, {file = "mypy-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8032e00ce71c3ceb93eeba63963b864bf635a18f6c0c12da6c13c450eedb183"}, {file = "mypy-1.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4c46b51de523817a0045b150ed11b56f9fff55f12b9edd0f3ed35b15a2809de0"}, {file = "mypy-1.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:19f905bcfd9e167159b3d63ecd8cb5e696151c3e59a1742e79bc3bcb540c42c7"}, {file = "mypy-1.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:82e469518d3e9a321912955cc702d418773a2fd1e91c651280a1bda10622f02f"}, {file = "mypy-1.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d4473c22cc296425bbbce7e9429588e76e05bc7342da359d6520b6427bf76660"}, {file = "mypy-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59a0d7d24dfb26729e0a068639a6ce3500e31d6655df8557156c51c1cb874ce7"}, {file = "mypy-1.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cfd13d47b29ed3bbaafaff7d8b21e90d827631afda134836962011acb5904b71"}, {file = "mypy-1.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:eb4f18589d196a4cbe5290b435d135dee96567e07c2b2d43b5c4621b6501531a"}, {file = "mypy-1.6.1-py3-none-any.whl", hash = "sha256:4cbe68ef919c28ea561165206a2dcb68591c50f3bcf777932323bc208d949cf1"}, {file = "mypy-1.6.1.tar.gz", hash = "sha256:4d01c00d09a0be62a4ca3f933e315455bde83f37f892ba4b08ce92f3cf44bcc1"}, ] [[package]] name = "mypy-extensions" version = "1.0.0" requires_python = ">=3.5" summary = "Type system extensions for programs checked with the mypy type checker." files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] [[package]] name = "transcrypt" version = "3.9.1" summary = "Python to JavaScript transpiler, supporting multiple inheritance and generating lean, highly readable code" dependencies = [ "mypy", ] files = [ {file = "Transcrypt-3.9.1-py2.py3-none-any.whl", hash = "sha256:73f5b3587f561aff66fa82f5fb3407f8b5950e991ad335f5f6dd889990ab0e10"}, ] [[package]] name = "typing-extensions" version = "4.8.0" requires_python = ">=3.8" summary = "Backported and Experimental Type Hints for Python 3.8+" files = [ {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ]
6. Google Closure Compiler
Nástroj Transcrypt ve skutečnosti při transpřekladu provádí několik operací:
- Převod zdrojového kódu Pythonu do AST (Abstract Syntax Tree)
- Transformace na úrovni AST
- Vygenerování JavaScriptového kódu z AST
- Optimalizace a minifikace výsledného JavaScriptového kódu
Pro poslední krok, tedy pro optimalizace a minifikace, se interně volá Google Closure Compiler. Tento krok je relativně pomalý (větší projekty budou optimalizovány řádově v sekundách), ovšem zásadnější je, že Google Closure Compiler vyžaduje JDK. To je buď nutné nainstalovat (což je téma navazující kapitoly) nebo lze alternativně optimalizaci a minifikaci vypnout zápisem přepínače -n. Výsledkem pak budou sice neoptimalizované, ale zato čitelné kódy v JavaScriptu, které budeme moci snadno porovnat s jejich Pythonovskými protějšky.
7. Instalace JDK pro Google Closure Compiler
V případě, že se nástrojem Transcrypt pokusíme přeložit (resp. přesněji řečeno transpřeložit) nějaký zdrojový soubor obsahující kód v Pythonu do JavaScriptu, bude se provádět následná optimalizace a minifikace kódu právě s využitím Google Closure Compileru. Ten je sice nainstalován současně s Transcryptem, ovšem samotné JDK již nikoli. To, zda je JDK dostupné či nikoli, lze snadno ověřit:
$ transcrypt test.py
nebo příkazem:
$ pdm run transcrypt test.py
Pokud se vypíše následující chyba (viz zvýrazněný řádek), je nutné doinstalovat celé JDK:
Saving target code in: /home/ptisnovs/test1/__target__/org.transcrypt.__runtime__.js Saving minified target code in: /home/ptisnovs/test1/__target__/org.transcrypt.__runtime__.js Error while compiling (offending file last): File 'org.transcrypt.__runtime__', line 0, namely: [Errno 2] No such file or directory: 'java' Aborted
8. Transpřeklad Pythonu do JavaScriptu
Spuštění transpřekladu je ve skutečnosti snadné. Vše si ukážeme na kódu hello.py, který je přímo součástí instalace Transcryptu (viz devatenáctou kapitolu). V případě, že máme nainstalován nástroj Transcrypt, můžeme transpřeklad spustit takto:
$ transcrypt hello.py
Popř. v případě, že používáme PDM, lze tranpřeklad spustit nepatrně odlišným příkazem:
$ pdm run transcrypt hello.py
Průběh překladu (transformace) je vypisován na terminál:
Transcrypt (TM) Python to JavaScript Small Sane Subset Transpiler Version 3.9.0 Copyright (C) Geatec Engineering. License: Apache 2.0 Saving target code in: /home/ptisnovs/test1/__target__/org.transcrypt.__runtime__.js Saving minified target code in: /home/ptisnovs/test1/__target__/org.transcrypt.__runtime__.js Saving target code in: /home/ptisnovs/test1/__target__/itertools.js Saving minified target code in: /home/ptisnovs/test1/__target__/itertools.js Saving target code in: /home/ptisnovs/test1/__target__/hello.js Saving minified target code in: /home/ptisnovs/test1/__target__/hello.js Ready
Původní zdrojový soubor měl velikost 1181 bajtů:
-rw-r--r--. 1 ptisnovs ptisnovs 1181 Oct 19 16:11 hello.py
Výsledkem je po optimalizaci a minifikaci soubor hello.js s délkou 2481 bajtů, přičemž cca kilobajt má řádek s importem:
-rw-r--r--. 1 ptisnovs ptisnovs 2481 Oct 19 16:14 hello.js -rw-r--r--. 1 ptisnovs ptisnovs 1167 Oct 19 16:14 hello.project -rw-r--r--. 1 ptisnovs ptisnovs 4367 Oct 19 16:14 itertools.js -rw-r--r--. 1 ptisnovs ptisnovs 43192 Oct 19 16:14 org.transcrypt.__runtime__.js
Pokud je optimalizace zakázána přepínačem -n, bude výsledný soubor nepatrně delší:
-rw-r--r--. 1 ptisnovs ptisnovs 2834 Oct 19 16:33 hello.js -rw-r--r--. 1 ptisnovs ptisnovs 1166 Oct 19 16:33 hello.project -rw-r--r--. 1 ptisnovs ptisnovs 7737 Oct 19 16:33 itertools.js -rw-r--r--. 1 ptisnovs ptisnovs 62007 Oct 19 16:33 org.transcrypt.__runtime__.js
Můžeme si spustit HTML server a zobrazit si stránku s příkladem (samotná HTML stránka načítá jak skript, tak i podpůrné runtime knihovny):
$ python3 -m http.server
V případě, že při transpilaci použijeme přepínač -m, vygeneruje se i soubor obsahující vazbu mezi řádky napsanými v JavaScriptu a řádky v původním zdrojovém kódu Pythonu (takzvaná source mapa). V praxi nám to umožní ladění, protože nás většinou příliš nezajímá, ve kterém místě vygenerovaného JavaScriptového kódu vznikla výjimka atd., ale o jaký se jedná řádek v původním kódu.
V našem konkrétním případě bude source mapa vypadat následovně:
{ "version": 3, "file": "hello.js", "sources": [ "hello.py" ], "mappings": "AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAWA;AAMA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAEA;AAAA;AAAA;AAEA;AAlCA" }
9. Překlad kódu, který manipuluje se seznamy, do JavaScriptu
Podívejme se nyní na způsob překladu některých základních programových konstrukcí z Pythonu do JavaScriptu. Oba zmíněné programovací jazyky mají mnoho společných rysů, což by mělo znamenat, že se i jejich konstrukce budou podobat. Začneme jednoduchým skriptem, který manipuluje se seznamy – vytváří seznam, přidává do něj další prvek a následně celý výsledný seznam vypíše:
x = [1, 2, 3, 4, 5] x.append(99) print(x) for item in x: print(item)
Po (trans)překladu do JavaScriptu získáme praktický stejný zdrojový kód, který bude pouze na začátku obsahovat import symbolů, které odpovídají standardní knihovně jazyka Python (důležitější je však ta část kódu, která následuje za importem):
// Transcrypt'ed from Python, 2023-10-19 16:36:48 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var x = [1, 2, 3, 4, 5]; x.append (99); print (x); for (var item of x) { print (item); } //# sourceMappingURL=lists.map
10. Překlad kódu, který manipuluje se slovníky, do JavaScriptu
Podobně se můžeme přesvědčit o tom, jak se do JavaScriptu přeloží kód, který manipuluje se slovníky:
x = {"foo": 1, "bar": 2, "baz": None} print(x) for key, value in enumerate(x): print(key, value)
Výsledný kód v JavaScriptu:
// Transcrypt'ed from Python, 2023-10-19 16:36:27 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var x = dict ({'foo': 1, 'bar': 2, 'baz': null}); print (x); for (var [key, value] of enumerate (x)) { print (key, value); } //# sourceMappingURL=maps.map
11. Transformace jednoduchých funkcí do JavaScriptu
Programovací jazyky Python a JavaScript mají velmi podobnou sémantiku funkcí (funkce jsou plnohodnotnými typy, lze pracovat s uzávěry atd.), takže by nemělo být větším překvapením, jak se transformují jednoduché funkce z Pythonu do JavaScriptu. Začneme opravdu triviálním příkladem (jehož chování však ve skutečnosti již tak triviální není – záleží na datových typech):
def add(a, b): return a+b
Překlad (transpřeklad) do JavaScriptu je v tomto případě poměrně přímočarý:
// Transcrypt'ed from Python, 2023-10-19 16:39:41 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var add = function (a, b) { return a + b; }; //# sourceMappingURL=adder1.map
12. Překlad rekurzivní funkce a taktéž generátoru range
Nyní se podívejme na způsob překladu funkce pro výpočet faktoriálu (která vrací hodnotu None pro neplatný vstup). Při testu této funkce se používá generátor range, který nemá v JavaScriptu přímou obdobu. Bude tedy zajímavé se podívat na výsledky transpřekladu tohoto příkladu:
def factorial(n): """Rekurzivní výpočet faktoriálu.""" assert isinstance(n, int), "Integer expected" if n < 0: return None if n == 0: return 1 result = n * factorial(n - 1) assert isinstance(result, int), "Internal error in factorial computation" return result def main(): for n in range(0, 11): print(n, factorial(n)) if __name__ == "__main__": main()
Samotná funkce pro výpočet faktoriálu se přeloží takto:
export var factorial = function (n) { if (n < 0) { return null; } if (n == 0) { return 1; } var result = n * factorial (n - 1); return result; };
A programová smyčka s range byla přeložena do explicitně zapsané počítané smyčky typu for:
for (var n = 0; n < 11; n++) { print (n, factorial (n)); }
Celý program po překladu do JavaScriptu vypadá takto:
// Transcrypt'ed from Python, 2023-10-19 16:44:39 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var factorial = function (n) { if (n < 0) { return null; } if (n == 0) { return 1; } var result = n * factorial (n - 1); return result; }; export var main = function () { for (var n = 0; n < 11; n++) { print (n, factorial (n)); } }; if (__name__ == '__main__') { main (); } //# sourceMappingURL=factorial.map
13. Překlad uzávěru z Pythonu do JavaScriptu
Již v předchozích kapitolách jsme si řekli, že jak jazyk Python, tak i JavaScript mají podobný přístup k sémantice funkcí. Týká se to i podpory uzávěrů, kdy má funkce (resp. přesněji řečeno kód uvnitř nějaké funkce) přístup k nelokálním symbolům. Tuto problematiku si můžeme ukázat na realizaci jednoduchého čítače s konstruktorem createCounter, jehož funkce (interní funkce next) přistupuje a dokonce i mění nelokální symbol counter:
def createCounter(): counter = 0 def next(): nonlocal counter counter += 1 return counter return next # # Spusteni testu. # def main(): counter1 = createCounter() counter2 = createCounter() for i in range(1,11): result1 = counter1() result2 = counter2() print("Iteration #%d" % i) print(" Counter1: %d" % result1) print(" Counter2: %d" % result2) main()
Překlad tohoto demonstračního příkladu do JavaScriptu je v tomto případě idiomatický, protože JavaScript (na rozdíl od Pythonu) nemá důvod pro použití speciálního sémantického a současně i syntaktického pravidla pro přístup k nelokálnímu symbolu:
// Transcrypt'ed from Python, 2023-10-19 16:42:46 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var createCounter = function () { var counter = 0; var py_next = function () { counter++; return counter; }; return py_next; }; export var main = function () { var counter1 = createCounter (); var counter2 = createCounter (); for (var i = 1; i < 11; i++) { var result1 = counter1 (); var result2 = counter2 (); print (__mod__ ('Iteration #%d', i)); print (__mod__ (' Counter1: %d', result1)); print (__mod__ (' Counter2: %d', result2)); } }; main (); //# sourceMappingURL=counter_closure.map
14. Funkce s pojmenovanými parametry
V Pythonu se navíc běžně používají funkce s pojmenovanými a nepovinnými parametry. Příkladem může být nepatrně upravený program s funkcí pro součet dvou hodnot, které nemusí být zadány:
def add(a=1, b=2): return a+b print(add()) print(add(10)) print(add(10, 20))
Tento koncept není JavaScriptem přímo podporován a proto si musel transpiler vypomoci:
// Transcrypt'ed from Python, 2023-10-23 14:42:17 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var add = function (a, b) { if (typeof a == 'undefined' || (a != null && a.hasOwnProperty ("__kwargtrans__"))) {; var a = 1; }; if (typeof b == 'undefined' || (b != null && b.hasOwnProperty ("__kwargtrans__"))) {; var b = 2; }; return a + b; }; print (add ()); print (add (10)); print (add (10, 20)); //# sourceMappingURL=adder2.map
15. Funkce vyhazující výjimku
Pro zajímavost si ještě vyzkoušejme nepatrnou úpravu výpočtu faktoriálu. Pro záporné vstupy budeme vyhazovat výjimku typu ValueError:
def factorial(n): """Rekurzivní výpočet faktoriálu.""" assert isinstance(n, int), "Integer expected" if n < 0: raise ValueError(n) if n == 0: return 1 result = n * factorial(n - 1) assert isinstance(result, int), "Internal error in factorial computation" return result def main(): for n in range(0, 11): print(n, factorial(n)) print(factorial(-1)) if __name__ == "__main__": main()
Výsledek transpilace je v tomto případě stále poměrně dobře čitelný, o čemž se můžeme velmi snadno přesvědčit:
// Transcrypt'ed from Python, 2023-10-23 14:44:23 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var factorial = function (n) { if (n < 0) { var __except0__ = ValueError (n); __except0__.__cause__ = null; throw __except0__; } if (n == 0) { return 1; } var result = n * factorial (n - 1); return result; }; export var main = function () { for (var n = 0; n < 11; n++) { print (n, factorial (n)); } print (factorial (-(1))); }; if (__name__ == '__main__') { main (); } //# sourceMappingURL=factorial2.map
16. Vykreslování na canvas (kreslicí plátno) na HTML stránce
Poměrně elegantním způsobem je vyřešeno vykreslování na canvas neboli kreslicí plochu, kterou lze v rámci HTML stránky vytvořit. V transpilovaném zdrojovém kódu je vykreslování řešeno přes další JavaScriptovou knihovnu, což nás však – programátory v Pythonu – ve skutečnosti nemusí příliš zajímat.
17. Text na kreslicím plátnu
Podívejme se nejdříve na to, jak lze zajistit vytvoření kreslicí plochy, načtení skriptu a jeho inicializaci se spuštěním:
<html> <head> <title>Canvas</title> <style> body { background: #dddddd; } #canvas { margin: 10px; padding: 10px; background: #ffffff; border: thin inset #aaaaaa; } </style> </head> <body> <canvas id='canvas' width='800' height='600'>Canvas not supported</canvas> <script type="module">import * as canvas from "./__target__/canvas1.js"; </script> </body> </html>
Vlastní skript psaný v Pythonu, který provádí vykreslování do kreslicí plochy, může vypadat následovně. Používáme zde dva základní grafické objekty – obrys textu a výplň textu:
canvas = document.getElementById('canvas') context = canvas.getContext('2d') context.font = '60pt Arial' context.fillStyle = 'darkblue' context.strokeStyle = 'navyblue' context.fillText('Hello Canvas', canvas.width / 2 - 210, canvas.height / 2 + 15) context.strokeText('Hello Canvas', canvas.width / 2 - 210, canvas.height / 2 + 15)
A takto vypadá výsledek transpilace výše uvedeného programu do JavaScriptu:
// Transcrypt'ed from Python, 2023-10-20 14:52:48 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var canvas = document.getElementById ('canvas'); export var context = canvas.getContext ('2d'); context.font = '60pt Arial'; context.fillStyle = 'darkblue'; context.strokeStyle = 'navyblue'; context.fillText ('Hello Canvas', canvas.width / 2 - 210, canvas.height / 2 + 15); context.strokeText ('Hello Canvas', canvas.width / 2 - 210, canvas.height / 2 + 15); //# sourceMappingURL=canvas1.map
$ python3 -m http.server
18. Cesta (path) na kreslicím plátnu
Podobně můžeme zkonstruovat a následně si nechat vykreslit takzvanou cestu (path). Ta může být složena z lineárních (úsečkových) segmentů, Bézierových kvadratických a kubických křivek a taktéž kruhových oblouků. Následující příklad je inspirován dokumentací Mozilly („obláček“):
canvas = document.getElementById('canvas') context = canvas.getContext('2d') context.fillStyle = 'darkblue' context.beginPath(); context.moveTo(75, 50); context.lineTo(100, 75); context.lineTo(100, 25); context.fill(); context.fillStyle = 'darkred' context.beginPath(); context.moveTo(225, 50); context.lineTo(200, 75); context.lineTo(200, 25); context.fill(); context.strokeStyle = 'darkgreen' context.lineWidth = 10; context.beginPath(); context.moveTo(75, 125); context.quadraticCurveTo(25, 125, 25, 162.5); context.quadraticCurveTo(25, 200, 50, 200); context.quadraticCurveTo(50, 220, 30, 225); context.quadraticCurveTo(60, 220, 65, 200); context.quadraticCurveTo(125, 200, 125, 162.5); context.quadraticCurveTo(125, 125, 75, 125); context.stroke();
Opět si, dnes již naposledy, ukažme, jak byl předchozí příklad transpilován do JavaScriptu:
// Transcrypt'ed from Python, 2023-10-20 14:52:22 import {AssertionError, AttributeError, BaseException, DeprecationWarning, Exception, IndexError, IterableError, KeyError, NotImplementedError, RuntimeWarning, StopIteration, UserWarning, ValueError, Warning, __JsIterator__, __PyIterator__, __Terminal__, __add__, __and__, __call__, __class__, __envir__, __eq__, __floordiv__, __ge__, __get__, __getcm__, __getitem__, __getslice__, __getsm__, __gt__, __i__, __iadd__, __iand__, __idiv__, __ijsmod__, __ilshift__, __imatmul__, __imod__, __imul__, __in__, __init__, __ior__, __ipow__, __irshift__, __isub__, __ixor__, __jsUsePyNext__, __jsmod__, __k__, __kwargtrans__, __le__, __lshift__, __lt__, __matmul__, __mergefields__, __mergekwargtrans__, __mod__, __mul__, __ne__, __neg__, __nest__, __or__, __pow__, __pragma__, __pyUseJsNext__, __rshift__, __setitem__, __setproperty__, __setslice__, __sort__, __specialattrib__, __sub__, __super__, __t__, __terminal__, __truediv__, __withblock__, __xor__, abs, all, any, assert, bool, bytearray, bytes, callable, chr, copy, deepcopy, delattr, dict, dir, divmod, enumerate, filter, float, getattr, hasattr, input, int, isinstance, issubclass, len, list, map, max, min, object, ord, pow, print, property, py_TypeError, py_iter, py_metatype, py_next, py_reversed, py_typeof, range, repr, round, set, setattr, sorted, str, sum, tuple, zip} from './org.transcrypt.__runtime__.js'; var __name__ = '__main__'; export var canvas = document.getElementById ('canvas'); export var context = canvas.getContext ('2d'); context.fillStyle = 'darkblue'; context.beginPath (); context.moveTo (75, 50); context.lineTo (100, 75); context.lineTo (100, 25); context.fill (); context.fillStyle = 'darkred'; context.beginPath (); context.moveTo (225, 50); context.lineTo (200, 75); context.lineTo (200, 25); context.fill (); context.strokeStyle = 'darkgreen'; context.lineWidth = 10; context.beginPath (); context.moveTo (75, 125); context.quadraticCurveTo (25, 125, 25, 162.5); context.quadraticCurveTo (25, 200, 50, 200); context.quadraticCurveTo (50, 220, 30, 225); context.quadraticCurveTo (60, 220, 65, 200); context.quadraticCurveTo (125, 200, 125, 162.5); context.quadraticCurveTo (125, 125, 75, 125); context.stroke (); //# sourceMappingURL=canvas2.map
19. Repositář s demonstračními příklady
Všechny Pythonovské skripty určené pro transpilaci do JavaScriptu, které jsme si v dnešním článku ukázali, naleznete společně s transpilovanými výsledky na adrese https://github.com/tisnik/most-popular-python-libs. Následují odkazy na jednotlivé příklady (pro jejich transpřeklad je nutné mít nainstalovánu některou z podporovaných verzí Pythonu 3, a pro dnešní příklady i výše popsaný nástroj transcrypt):
20. Odkazy na Internetu
- Stránky projektu Transcrypt
https://www.transcrypt.org/ - Balíček Transcrypt na PyPi
https://pypi.org/project/Transcrypt/ - Transcrypt na GitHubu
https://github.com/TranscryptOrg/Transcrypt - Transcrypt: getting started
https://www.transcrypt.org/docs/html/installation_use.html - Numscrypt: A tiny bit of NumPy for Transcrypt, using JavaScript typed arrays
https://www.transcrypt.org/numscrypt/numscrypt.html - Google Closure Compiler
https://github.com/google/closure-compiler - Statické typové kontroly zdrojových kódů Pythonu prováděné nástrojem Mypy
https://www.root.cz/clanky/staticke-typove-kontroly-zdrojovych-kodu-pythonu-provadene-nastrojem-mypy/ - Statické typové kontroly zdrojových kódů Pythonu prováděné nástrojem Mypy (2.část)
https://www.root.cz/clanky/staticke-typove-kontroly-zdrojovych-kodu-pythonu-provadene-nastrojem-mypy-2-cast/ - Statické typové kontroly zdrojových kódů Pythonu prováděné nástrojem Mypy (3)
https://www.root.cz/clanky/staticke-typove-kontroly-zdrojovych-kodu-pythonu-provadene-nastrojem-mypy-3/ - PyScript
https://pyscript.net/ - PyScript na GitHubu
https://github.com/pyscript/pyscript - Getting started with PyScript
https://github.com/pyscript/pyscript/blob/main/docs/tutorials/getting-started.md - PyScript examples
https://github.com/pyscript/pyscript/tree/main/examples - What is PyScript
https://docs.pyscript.net/latest/concepts/what-is-pyscript.html - Pyodide
https://pyodide.org/en/stable/ - PyScript: JavaScript and Python Interoperability
https://www.jhanley.com/blog/pyscript-javascript-and-python-interoperability/ - Pyscript: JavaScript Event Callbacks
https://www.jhanley.com/blog/pyscript-javascript-callbacks/ - Compiling to WebAssembly: It’s Happening!
https://hacks.mozilla.org/2015/12/compiling-to-webassembly-its-happening/ - WebAssembly
https://webassembly.org/ - Blogy o WASM a Emscripten
https://www.jamesfmackenzie.com/sitemap/#emscripten - wat2wasm demo
https://webassembly.github.io/wabt/demo/wat2wasm/ - WABT: The WebAssembly Binary Toolkit
https://github.com/WebAssembly/wabt - Programming using Web Assembly
https://medium.com/@alexc73/programming-using-web-assembly-c4c73a4e09a9 - Experiments with image manipulation in WASM using Go
https://agniva.me/wasm/2018/06/18/shimmer-wasm.html - Fable
https://fable.io/ - Využití WebAssembly z programovacího jazyka Go
https://www.root.cz/clanky/vyuziti-webassembly-z-programovaciho-jazyka-go/ - WebAssembly prošlo standardizací ve W3C, byla vydána verze 1.0
https://www.root.cz/zpravicky/webassembly-proslo-standardizaci-ve-w3c-byla-vydana-verze-1–0/ - 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/ - S-expression
https://en.wikipedia.org/wiki/S-expression - Understanding WebAssembly text format
https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format - Learning Golang through WebAssembly – Part 1, Introduction and setup
https://www.aaron-powell.com/posts/2019–02–04-golang-wasm-1-introduction/ - Learning Golang through WebAssembly – Part 2, Writing your first piece of Go
https://www.aaron-powell.com/posts/2019–02–05-golang-wasm-2-writing-go/ - Learning Golang through WebAssembly – Part 3, Interacting with JavaScript from Go
https://www.aaron-powell.com/posts/2019–02–06-golang-wasm-3-interacting-with-js-from-go/ - Golang webassembly (wasm) testing with examples
https://jelinden.fi/blog/golang-webassembly-wasm-testing-with-examples/qB7Tb2KmR - Use Cases (of WebAssembly)
https://webassembly.org/docs/use-cases/ - JupyterLite na PyPi
https://pypi.org/project/jupyterlite/ - JupyterLite na GitHubu
https://github.com/jupyterlite/jupyterlite - Dokumentace k projektu JupyterLite
https://github.com/jupyterlite/jupyterlite - A quick guide about Python implementations
https://blog.rmotr.com/a-quick-guide-about-python-implementations-aa224109f321 - 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 - What is Brython?
https://medium.com/frontendweb/what-is-brython-6edb424b07f6 - Python in browser (tabulka s porovnáními)
http://stromberg.dnsalias.org/~strombrg/pybrowser/python-browser.html - JavaScript is Assembly Language for the Web: Sematic Markup is Dead! Clean vs. Machine-coded HTML
http://www.hanselman.com/blog/JavaScriptIsAssemblyLanguageForTheWebSematicMarkupIsDeadCleanVsMachinecodedHTML.aspx - pyscript VS brython
https://www.libhunt.com/compare-pyscript-vs-brython - PyScript – Run Python in the Browser! THE END of JavaScript???
https://www.youtube.com/watch?v=du8vQC44PC4 - PyScript is Python in Your Browser
https://www.youtube.com/watch?v=MJvCeKwr4z4 - JupyterLite na PyPi
https://pypi.org/project/jupyterlite/ - JupyterLite na GitHubu
https://github.com/jupyterlite/jupyterlite - Dokumentace k projektu JupyterLite
https://github.com/jupyterlite/jupyterlite - Matplotlib Home Page
http://matplotlib.org/ - Matplotlib (Wikipedia)
https://en.wikipedia.org/wiki/Matplotlib - Popis barvových map modulu matplotlib.cm
https://gist.github.com/endolith/2719900#id7 - Ukázky (palety) barvových map modulu matplotlib.cm
http://matplotlib.org/examples/color/colormaps_reference.html - Galerie grafů vytvořených v Matplotlibu
https://matplotlib.org/3.2.1/gallery/ - Replacing Javascript with Python
https://stackoverflow.com/questions/69510962/replacing-javascript-with-python - Can Python Replace Javascript in the Future?
https://dev.to/katholder/can-python-replace-javascript-in-the-future-4bbn - asm.js
http://asmjs.org/ - asm.js: Working Draft
http://asmjs.org/spec/latest/ - Manual asm.js Demonstration
https://www.youtube.com/watch?v=qkiqMuf5M84 - asm.js – frequently asked questions
http://asmjs.org/faq.html - When asm.js is faster than normal JS code, why should I write new code in JS?
https://stackoverflow.com/questions/16527195/when-asm-js-is-faster-than-normal-js-code-why-should-i-write-new-code-in-js - Faster Canvas Pixel Manipulation with Typed Arrays
https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipulation-with-typed-arrays/ - Anatomy of source maps
https://www.bugsnag.com/blog/source-maps/ - Source Map Revision 3 Proposal
https://sourcemaps.info/spec.html