Obsah
2. Atributy transformované funkce vytvořené s využitím dekorátoru
3. Využití dekorátoru @wraps pro automatickou úpravu atributů „obalované“ funkce
4. Dekorátor @wraps a několikanásobná aplikace dekorátorů na „obalovanou“ funkci
5. Když možnosti functools už nedostačují: další knihovny pro podporu funkcionálního programování
8. Zkrácená deklarace dekorátoru s využitím dekorátoru @decorator
9. Několikanásobná aplikace dekorátorů
10. Přepis dekorátoru pro zjištění doby běhu funkce
11. Curryfikace funkce s využitím curry
12. Příklad curryfikace funkce se dvěma parametry
13. Curryfikace funkce se třemi parametry
14. Rozdíl mezi curryfikací funkce s využitím curry a rcurry
16. Kompozice funkcí s využitím funkce vyššího řádu compose
17. Kompozice zleva doprava či zprava doleva?
18. Repositář s demonstračními příklady
19. Příloha: odkazy na články o programovacím jazyku Clojure
1. Když možnosti functools nedostačují: další knihovny pro podporu funkcionálního programování pro Python
V předchozí trojici článků [1] [2] [3] jsme se zaměřili na ty funkcionální prvky programovacího jazyka Python, které jsou realizovány ve standardní knihovně nazvané příznačně functools. Ovšem na tomto místě je nutno říci, že tato knihovna je pojata poměrně minimalistickým způsobem a nalezneme v ní pouze některé techniky. Co nám ale vlastně ještě chybí? V první řadě lepší podpora pro tvorbu dekorátorů, podpora pro currying funkcí (když se smíříme s tím, že to nedokáže vlastní interpret Pythonu) a v neposlední řadě i podpora pro kompozici funkcí. Jednou z knihoven, která tyto techniky do Pythonu přináší, je knihovna funcy, s jejímiž naprostými základy se seznámíme dnes.
2. Atributy transformované funkce vytvořené s využitím dekorátoru
V předchozím článku jsme se (kromě dalších věcí) seznámili i se způsobem „obalení“ nějaké funkce dalšími příkazy a popř. i nelokálními proměnnými. Připomeňme si, že tato technologie je umožněna díky tomu, že funkce jsou v Pythonu plnohodnotnými datovými typy a tím pádem je (mj.) možné tvořit i uzávěry (closure). Obalení libovolné funkce kódem uvedeným ve funkci wrapper1 se syntakticky řeší takzvaným dekorátorem, v tomto konkrétním případě dekorátorem @wrapper1:
def wrapper1(function): def inner_function(): print("-" * 40) function() print("-" * 40) return inner_function @wrapper1 def hello(): print("Hello!") hello()
Vše bude fungovat zdánlivě bez problémů, ovšem nová funkce, která vznikne aplikací dekorátoru (už se totiž v žádném případě nejedná o původní funkci hello), bude mít některé své atributy nastaveny z pohledu uživatele poněkud matoucím způsobem. Můžeme si to ostatně velmi snadno otestovat:
print("function name:", hello.__name__)
Výsledek bude pro uživatele takové funkce matoucí a navíc i nejednoznačný v případě, kdy použijeme dekorátor wrapper1 vícekrát:
function name: inner_function
3. Využití dekorátoru @wraps pro automatickou úpravu atributů „obalované“ funkce
Problém zmíněný v předchozí kapitole lze velmi snadno vyřešit použitím (dalšího) dekorátoru pojmenovaného @wraps, který nalezneme v balíčku functools. Tento dekorátor se však neaplikuje na uživatelskou funkci, kterou je třeba transformovat, ale na nově vznikající funkci definovanou ve wrapperu a vracenou jako jeho návratovou hodnota. Celá úprava demonstračního příkladu z předchozí kapitoly bude vypadat následovně (dekorátor byl přidán k funkci inner_function):
from functools import wraps def wrapper1(function): @wraps(function) def inner_function(): print("-" * 40) function() print("-" * 40) return inner_function @wrapper1 def hello(): print("Hello!") hello() print("function name:", hello.__name__)
Výsledek bude nyní vypadat následovně:
---------------------------------------- Hello! ---------------------------------------- function name: hello
4. Dekorátor @wraps a několikanásobná aplikace dekorátorů na „obalovanou“ funkci
Dekorátor @wraps, s nímž jsme se ve stručnosti seznámili v předchozím textu, je „tranzitivní“ ve smyslu, že pomůže zachovat původní jméno (popř. i další atributy) funkce, která je transformována větším množstvím dekorátorů. Opět se podívejme na vhodný demonstrační příklad, který vychází z nám již známého příkladu, kdy funkci hello transformujeme s využitím dekorátorů nazvaných jednoduše @wrapper1 @wrapper2:
from functools import wraps def wrapper1(function): @wraps(function) def inner_function(): print("-" * 40) function() print("-" * 40) return inner_function def wrapper2(function): @wraps(function) def inner_function(): print("=" * 40) function() print("=" * 40) return inner_function @wrapper1 @wrapper2 def hello(): print("Hello!") hello() print("function name:", hello.__name__)
V případě, že tento skript spustíme, vypíšou se nejdříve zprávy produkované transformovanou funkcí, resp. přesněji řečeno funkcí obalenou dvojicí dekorátorů. A na posledním řádku se korektně vypíše původní jméno funkce, které by jinak bylo ztraceno při transformaci (protože se technicky již jedná o funkci nazvanou inner_function):
---------------------------------------- ======================================== Hello! ======================================== ---------------------------------------- function name: hello
5. Když možnosti functools už nedostačují: další knihovny pro podporu funkcionálního programování
V této sérii článků jsme si popsali většinu vlastností standardní knihovny functools, která do Pythonu přináší některé prvky funkcionálního programování. Ovšem některé funkcionální vlastnosti tato knihovna nepokrývá či pokrývá jen částečně. Jedná se jak o podporu kompozice funkcí, popř. curryingu (i když partial je částečným (sic) řešením), tak i například o podporu pro neměnitelné datové typy, funkcí pro zpracování sekvencí, podporu typů Option či Result (tak jsou pojmenované v Rustu) atd. Z tohoto důvodu vznikla celá řada více či méně obsáhlých balíčků, z nichž mnohé jsou vyjmenovány (a podle oblíbenosti seřazeny) na stránce Awesome functional Python. V dalším textu se postupně zaměříme především na balíčky Funcy, (Py)Toolz a taktéž Fn.py:
- Funcy na GitHubu
https://github.com/suor/funcy/ - PyToolz API Documentation
https://toolz.readthedocs.io/en/latest/index.html - Toolz (PyToolz) na GitHubu
https://github.com/pytoolz/toolz - Fn.py: enjoy FP in Python
https://github.com/kachayev/fn.py
6. Knihovna funcy
První z knihoven, které do Pythonu přidávají další funkcionální prvky, se jmenuje funcy. Autor této knihovny se nechal inspirovat především vlastnostmi programovacího jazyka Clojure a taktéž vlastnostmi knihovny Underscore (či Lodash) pro ekosystém JavaScriptu. S Clojure jsme se již na stránkách Rootu seznámili v samostatně běžícím seriálu (viz odkazy na konci dnešního článku) a věnovali jsme se i knihovně Underscore, a to konkrétně v článcích Underscore aneb další knihovna pro funkcionální programování v JavaScriptu a Funkce vyššího řádu v knihovně Underscore. Jaké možnosti, vlastnosti a techniky tedy byly z těchto dvou použity v knihovně funcy? Podívejme se na jejich seznam:
- Funkce pro zpracování sekvencí (což je abstrakce postavená nad seznamy, n-ticemi atd.)
- Funkce pro zpracování kolekcí
- Zpracování funkcí – currying, kompozice funkcí a mnoho dalších podobných operací
- Podpora pro práci s dekorátory
- Podpůrné funkcionální konstrukce pro řízení toku (control flow), typicky založeném na použití dekorátorů a funkcí vyššího řádu
- Podpora pro ladění
- Podpora pro caching (v poněkud rozšířeném významu oproti nám již známé @lru_cache a @cached_property)
7. Instalace knihovny funcy
Samotná instalace knihovny funcy je velmi snadná, protože tato knihovna neobsahuje žádné překládané části (proto ani její wheel nerozlišuje mezi architekturami) a ani nemá žádné další závislosti:
$ pip3 install --user funcy Collecting funcy Downloading funcy-2.0-py2.py3-none-any.whl (30 kB) Installing collected packages: funcy Successfully installed funcy-2.0
Nejedná se přitom o nijak obsáhlý balíček, protože jeho zdrojové kódy mají přibližně 2500 řádků:
$ wc -l .local/lib/python3.8/site-packages/funcy/*.py 152 .local/lib/python3.8/site-packages/funcy/calc.py 362 .local/lib/python3.8/site-packages/funcy/colls.py 43 .local/lib/python3.8/site-packages/funcy/compat.py 243 .local/lib/python3.8/site-packages/funcy/debug.py 184 .local/lib/python3.8/site-packages/funcy/decorators.py 246 .local/lib/python3.8/site-packages/funcy/flow.py 28 .local/lib/python3.8/site-packages/funcy/funcmakers.py 27 .local/lib/python3.8/site-packages/funcy/funcolls.py 135 .local/lib/python3.8/site-packages/funcy/funcs.py 21 .local/lib/python3.8/site-packages/funcy/__init__.py 182 .local/lib/python3.8/site-packages/funcy/_inspect.py 107 .local/lib/python3.8/site-packages/funcy/objects.py 28 .local/lib/python3.8/site-packages/funcy/primitives.py 41 .local/lib/python3.8/site-packages/funcy/py2.py 32 .local/lib/python3.8/site-packages/funcy/py3.py 504 .local/lib/python3.8/site-packages/funcy/seqs.py 78 .local/lib/python3.8/site-packages/funcy/strings.py 40 .local/lib/python3.8/site-packages/funcy/tree.py 26 .local/lib/python3.8/site-packages/funcy/types.py 2479 total
Vyzkoušejme si pro jistotu, zda je možné knihovnu funcy naimportovat a zobrazit si nápovědu k ní:
>>> import funcy >>> help(funcy)
Po zadání těchto příkazů by se na terminálu měla zobrazit nápověda k naimportovanému balíčku:
Help on package funcy: NAME funcy PACKAGE CONTENTS _inspect calc colls compat debug decorators flow funcmakers funcolls funcs objects primitives py2 py3 seqs strings tree types
8. Zkrácená deklarace dekorátoru s využitím dekorátoru @decorator
Podívejme se nejprve znovu na téma, kterému jsme se věnovali v závěru předchozího článku i na začátku článku dnešního – jak v Pythonu vytvořit dekorátor, tedy vhodně zapsanou funkci, která obalí/transformuje uživatelem zadanou funkci. Víme již, že základní řešení může vypadat následovně:
def wrapper1(function): def inner_function(): print("-" * 40) function() print("-" * 40) return inner_function @wrapper1 def hello(): print("Hello!") hello()
Toto řešení je čitelné z pohledu uživatele dekorátoru a jeho další výhodou je, že nic neskrývá, protože ze zdrojového kódu funkce wrapper1 je přímo patrné, jaká operace se zde provádí. Na druhou stranu by možná bylo vhodnější si celý zápis zkrátit a zbytečně se nezabývat deklarací wrapperu, prací s interní funkcí, kterou wrapper vrací atd. A právě v takovém případě lze při použití knihovny funcy pro deklaraci dekorátoru použít jiný dekorátor, zde konkrétně dekorátor nazvaný přímočaře @decorator. Jeho použití je až triviálně snadné, protože vlastně namísto původního wrapperu píšeme jen deklaraci „obalovací“ funkce:
from funcy import decorator @decorator def wrapper1(function): print("-" * 40) function() print("-" * 40) @wrapper1 def hello(): print("Hello!") hello()
9. Několikanásobná aplikace dekorátorů
Pro úplnost se ještě podívejme na další již známý příklad. Jedná se o několikanásobnou aplikaci více dekorátorů, což znamená, že původní funkce je transformována do jiné funkce a ta je dále transformována do další funkce (atd.). Připomeňme si, že zdrojový kód tohoto příkladu vypadal takto:
def wrapper1(function): def inner_function(): print("-" * 40) function() print("-" * 40) return inner_function def wrapper2(function): def inner_function(): print("=" * 40) function() print("=" * 40) return inner_function @wrapper1 @wrapper2 def hello(): print("Hello!") hello()
Opět se podívejme na způsob zjednodušení celé struktury tohoto příkladu do podoby založené na použití dekorátoru @decorator. Přepis je přímočarý:
from funcy import decorator @decorator def wrapper1(function): print("-" * 40) function() print("-" * 40) @decorator def wrapper2(function): print("=" * 40) function() print("=" * 40) @wrapper1 @wrapper2 def hello(): print("Hello!") hello()
10. Přepis dekorátoru pro zjištění doby běhu funkce
Naposledy se podívejme na použití dekorátoru @decorator z balíčku funcy. Tentokráte upravíme příklad s dekorátorem, který dokáže změnit délku trvání nějaké operace v měřené funkci. Původní zápis vypadal následovně:
# Original code: # https://pythonbasics.org/decorators/#Real-world-examples import time def measure_time(func): def wrapper(*arg): t = time.time() res = func(*arg) print("Function took " + str(time.time() - t) + " seconds to run") return res return wrapper @measure_time def tested_function(n): time.sleep(n) tested_function(1) tested_function(2)
Přepis do stručnější a čitelnější podoby:
from funcy import decorator import time @decorator def measure_time(func): t = time.time() res = func() print("Function took " + str(time.time() - t) + " seconds to run") return res @measure_time def tested_function(n): print(f"Sleeping for {n} seconds") time.sleep(n) tested_function(1) tested_function(2)
11. Curryfikace funkce s využitím curry
Ve třetí části dnešního článku si ukážeme, jakým způsobem se v programovacím jazyku Python s využitím knihovny funcy provádí takzvaná curryfikace (anglicky currying). Pod tímto termínem se v teorii programovacích jazyků (ovšem i obecně v matematice) označuje proces, jímž se transformuje funkce, která akceptuje více než jeden parametr, do řady vložených funkcí, přičemž každá z nich akceptuje jen jediný parametr. Curryfikaci si můžeme představit jako postupnou transformaci funkce s n parametry na jinak zkonstruovanou funkci s n-1 parametry atd. až rekurzivně dojdeme k funkci s jediným parametrem:
x = f(a,b,c) → h = g(a) i = h(b) x = i(c)
Nebo na jediném řádku:
x = f(a,b,c) → g(a)(b)(c)
12. Příklad curryfikace funkce se dvěma parametry
Pro otestování možností, které nám nabízí funkce vyššího řádu curry se pokusme o curryfikaci funkce add se dvěma parametry x a y. Výsledkem curryfikace by měla být funkce s jediným parametrem x, která vrací jinou funkci akceptující taktéž jediný parametr (tentokrát y) a teprve po zavolání této funkce se vrátí kýžený výsledek – součet dvou numerických hodnot:
from funcy import curry def add(x, y): return x + y curried = curry(add) print(curried) print(curried(1)) print(curried(1)(2)) # pozor na umístění závorek!
Podívejme se nyní na vypsané výsledky:
<function curry.<locals>.<lambda> at 0x7efd464f0160> <function curry.<locals>.<lambda>.<locals>.<lambda> at 0x7efd463350d0> 3
Jak máme tyto výsledky interpretovat?
- První řádek popisuje funkci (a my víme, že má jeden parametr)
- Druhý řádek vznikl voláním této funkce a výsledkem je jiná funkce (opět akceptující jeden parametr, jak již víme)
- A konečně řádek třetí vznikl zavoláním této funkce s kýženým výsledkem 3
13. Curryfikace funkce se třemi parametry
Ve skutečnosti pochopitelně není curryfikace omezena pouze na funkce se dvěma parametry. Podívejme se tedy na to, jak bude vypadat curryfikace funkce, která akceptuje tři parametry. Pro jednoduchost použijeme funkci, která své tři parametry sečte a vrátí výsledek součtu:
from funcy import curry def add3(x, y, z): return x + y + z curried = curry(add3) print(curried) print(curried(1)) print(curried(1)(2)) # pozor na umístění závorek! print(curried(1)(2)(3)) # pozor na umístění závorek!
Po spuštění tohoto skriptu získáme na standardním výstupu následující čtyři řádky:
<function curry.<locals>.<lambda> at 0x7f3ea21d1160> <function curry.<locals>.<lambda> at 0x7f3ea20160d0> <function curry.<locals>.<lambda>.<locals>.<lambda> at 0x7f3ea1fa9f70> 6
Postupně se jedná o tyto hodnoty:
- Funkce akceptující jeden parametr a vracející novou funkci (která bude opět vracet funkci akceptující jeden parametr).
- Funkce akceptující jeden parametr a vracející novou funkci (která již bude vracet konkrétní číselnou hodnotu).
- Funkce akceptující jeden parametr, která vrátí výsledek součtu tohoto parametru se svou vnitřní hodnotou 1+2.
- Výsledek volání poslední funkce (z předchozího řádku) s parametrem 3.
14. Rozdíl mezi curryfikací funkce s využitím curry a rcurry
Prozatím jsme si curryfikaci ukazovali na dvojici funkcí, jejichž parametry vlastně byly komutativní, protože nezáleželo na jejich pořadí. To sice ve skutečnosti není zcela pravda, protože interní stavy mezifunkcí již na pořadí parametrech závisí, ovšem výsledkem bude pro stejné parametry (bez ohledu na jejich pořadí) stejná hodnota (pochopitelně za předpokladu, že se jedná o celá čísla). Ovšem podívejme se na funkci, kde již na pořadí parametrů záleží. Bude se jednat o funkci pro výpočet podílu hodnot parametrů, takže se zde striktně rozlišuje mezi dělencem a dělitelem:
from funcy import curry def div(x, y): return x / y curried = curry(div) print(curried) print(curried(1)) print(curried(1)(2)) # pozor na umístění závorek!
Nyní budou výsledky (zejména poslední řádek) vypadat takto:
<function curry.<locals>.<lambda> at 0x7facbefbf160> <function curry.<locals>.<lambda>.<locals>.<lambda> at 0x7facbee040d0> 0.5
To by nemělo být příliš překvapující, protože výsledkem podílu 1/2 je za určitých předpokladů :-) (správná verze Pythonu) skutečně hodnota 0.5.
Ovšem knihovna funcy nabízí programátorům i funkci nazvanou rcurry, která provádí currying od posledního argumentu k argumentu prvnímu, tedy v opačném pořadí. Pro nekomutativní parametry se bude výsledek lišit (a nejen to – zde se dokonce projeví i případná ne-asociativita). Ostatně se podívejme sami, jak se bude lišit výsledek získaný po curryfikaci pomocí rcurry a nikoli pomocí curry:
from funcy import rcurry def div(x, y): return x / y curried = rcurry(div) print(curried) print(curried(1)) print(curried(1)(2)) # pozor na umístění závorek!
Výsledek bude následující:
<function rcurry.<locals>.<lambda> at 0x7f921d37c160> <function rcurry.<locals>.<lambda>.<locals>.<lambda> at 0x7f921d1c10d0> 2.0
Nyní se můžete ptát, k čemu je to vlastně dobré. Ve skutečnosti se může jednat o poměrně užitečnou techniku, jak je to ostatně ukázáno i v dokumentaci. My si ukážeme odlišný příklad, a to generátor funkcí pro výpočet libovolné dopředu zvolené mocniny. Generované funkce tedy budou akceptovat hodnotu x a vrátí xy, kde y je již ve vygenerovaných funkcích pevně „zadrátováno“:
from funcy import rcurry def pow(x, y): return x ** y n_pow = rcurry(pow) pow2 = n_pow(2) pow10 = n_pow(10) print(pow2(2)) print(pow10(2))
Funkce pow2 a pow10 byly vygenerovány zavoláním funkce n_pow a předáním mocniny:
4 1024
Z druhého výsledku je zřejmé, že se vrátila hodnota 210.
15. „autocurryfikace“
Knihovna funcy jde ovšem ještě dále a kromě „běžných“ funkcí vyššího řádu curry a ncurry nabízí vývojářům ještě jednu curryfikační techniku. Ta je implementována ve funkci vyššího řádu nazvané autocurry. Tato funkce opět akceptuje libovolnou jinou funkci s libovolným počtem parametrů a vrací novou funkci, která se chová jako vzorně curryfikovaná funkce (akceptuje tedy jeden parametr a obecně vrací jinou funkci), ale současně se chová i jako funkce, na kterou jsou aplikovány všechny kombinace partial. Což znamená, že nově vzniklé funkci můžete předat libovolné množství parametrů (až do maxima omezeného původní funkcí) a buď se vrátí curryfikovaná či částečně aplikovaná funkce nebo přímo výsledek.
Zní to složitě? Podívejme se na příklad:
from funcy import autocurry def pow(x, y): return x ** y n_pow = autocurry(pow) powX = n_pow() pow2 = n_pow(2) pow10 = n_pow(10) pow3to3 = n_pow(3, 3) print(powX(3, 3)) print(pow2(2)) print(pow10(2)) print(pow3to3)
Na řádku:
n_pow = autocurry(pow)
jsme si vyžádali vygenerování nové funkce, která je jak curryfikovanou obdobou vstupní funkce, tak i funkce, která se bude chovat, jako bychom použili partial. To je ostatně patrné na následujících čtyřech řádcích:
powX = n_pow() # curryfikace/partial bez parametrů (pochopitelně se vrací funkce) pow2 = n_pow(2) # curryfikace pow10 = n_pow(10) # curryfikace pow3to3 = n_pow(3, 3) # partial, ovšem dosazením všech parametrů ihned získáme výsledek (nevrací se funkce)
A výsledky:
27 4 100 # 10^2 nikoli 2^10 !!! 27
16. Kompozice funkcí s využitím funkce vyššího řádu compose
V několika funkcionálních jazycích (a taktéž v jazycích typu FORTH, Factor nebo Joy) je umožněno vytvářet kompozice funkcí, tj. nové funkce, které vzniknou vzájemným voláním funkcí existujících, ovšem s tím, že se při konstrukci kompozice neřeší takové „maličkosti“, jako jsou názvy či počty předávaných parametrů. Ovšem s kompozicí funkcí se setkáme i v dalších jazycích, i když zde se celá technika může nazývat jinak (pipeline) atd.
Podívejme se na velmi jednoduchý příklad, který provede kompozici standardních funkcí len a str, a to konkrétně tak, že se vstupní parametr převede na řetězec funkcí str a následně se vypočte a vrátí délka tohoto řetězce funkcí len. Kompozice je tedy len(str(vstup)):
from funcy import compose composed = compose(len, str) print(composed) print(composed(0)) print(composed(42)) print(composed(1000))
Výsledek by měl vypadat následovně – nejprve se vypíše typ hodnoty composed a následně se vypíšou délky řetězců „0“, „42“ a „1000“:
<function compose.<locals>.<lambda>.<locals>.<lambda> at 0x7f5bf7100160> 1 2 4
Ovšem můžeme použít i funkce s větším množstvím parametrů. Například lze vytvořit kompozici z funkce pro součet dvou hodnot s následným vynásobením mezivýsledku dvojkou:
from funcy import compose def add(x, y): return x+y def double(x): return 2*x composed = compose(double, add) print(composed(2, 3)) print(composed(-2, -3))
Takto vypadají výsledky:
10 -10
A pro úplnost si ukažme ještě kompozici získanou ze třech funkcí, konkrétně abs(double(add(x,y))):
from funcy import compose def add(x, y): return x+y def double(x): return 2*x def abs(x): if x < 0: return -x return x composed = compose(abs, double, add) print(composed(2, 3)) print(composed(-2, -3))
S výsledkem:
10 10
17. Kompozice zleva doprava či zprava doleva?
Při tvorbě pipeline z funkcí je přirozenější číst kompozici zleva doprava. V tomto případě je výhodnější namísto compose použít funkci vyššího řádu nazvanou rcompose:
from funcy import rcompose composed = rcompose(str, len) print(composed) print(composed(0)) print(composed(42)) print(composed(1000))
Výsledky budou odpovídat příkladu z předchozí kapitoly:
<function compose.<locals>.<lambda>.<locals>.<lambda> at 0x7f9795247160> 1 2 4
Podobně můžeme přepsat i druhý příklad z předchozí kapitoly do této přehlednější podoby:
from funcy import rcompose def add(x, y): return x+y def double(x): return 2*x composed = rcompose(add, double) print(composed(2, 3)) print(composed(-2, -3))
Výsledky:
10 -10
A poslední příklad byl přepsán do této pipeline:
from funcy import rcompose def add(x, y): return x+y def double(x): return 2*x def abs(x): if x < 0: return -x return x composed = rcompose(add, double, abs) print(composed(2, 3)) print(composed(-2, -3))
Výsledky:
10 10
18. Repositář s demonstračními příklady
Všechny Pythonovské skripty, které jsme si ukázali v úvodním článku, předminule, minule i dnes, naleznete na adrese https://github.com/tisnik/most-popular-python-libs. Následují odkazy na jednotlivé příklady (pro jejich spuštění je nutné mít nainstalovánu některou z podporovaných verzí Pythonu 3, a pro dnešní příklady i výše zmíněnou knihovnu funcy):
19. Příloha: odkazy na články o programovacím jazyku Clojure
Pro úplnost si uveďme odkazy na články o programovacím jazyku Clojure, jenž byl, podobně jako knihovna Underscore, velkou inspirací pro tvorbu knihovny funcy. Mnoho technik je v Clojure pojmenováno stejně či velmi podobně, jako ve tomu funcy atd.:
- Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - Programovací jazyk Clojure – práce s mapami a množinami
http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/ - Programovací jazyk Clojure – základy zpracování XML
http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/ - Programovací jazyk Clojure – testování s využitím knihovny Expectations
http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/ - Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/ - Enlive – výkonný šablonovací systém pro jazyk Clojure
http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/ - Nástroj Leiningen a programovací jazyk Clojure: tvorba vlastních knihoven pro veřejný repositář Clojars
http://www.root.cz/clanky/nastroj-leiningen-a-programovaci-jazyk-clojure-tvorba-vlastnich-knihoven-pro-verejny-repositar-clojars/ - Novinky v Clojure verze 1.8.0
http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/ - Asynchronní programování v Clojure s využitím knihovny core.async
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async/ - Asynchronní programování v Clojure s využitím knihovny core.async (pokračování)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-pokracovani/ - Asynchronní programování v Clojure s využitím knihovny core.async (dokončení)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-dokonceni/ - Vytváříme IRC bota v programovacím jazyce Clojure
http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/ - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Multimetody v Clojure aneb polymorfismus bez použití OOP
https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/ - Práce s externími Java archivy v programovacím jazyku Clojure
https://www.root.cz/clanky/prace-s-externimi-java-archivy-v-programovacim-jazyku-clojure/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vim s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/ - Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v azyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/ - Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
https://www.root.cz/clanky/programovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/ - Novinky v Clojure verze 1.9.0
https://www.root.cz/clanky/novinky-v-clojure-verze-1–9–0/ - Validace dat s využitím knihovny spec v Clojure 1.9.0
https://www.root.cz/clanky/validace-dat-s-vyuzitim-knihovny-spec-v-clojure-1–9–0/ - Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure
https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure/ - Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure (2)
https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure-2/ - Incanter: prostředí pro statistické výpočty s grafickým výstupem založené na Clojure
https://www.root.cz/clanky/incanter-prostredi-pro-statisticke-vypocty-s-grafickym-vystupem-zalozene-na-clojure/ - Incanter: operace s maticemi
https://www.root.cz/clanky/incanter-operace-s-maticemi/ - Interpret programovacího jazyka Clojure integrovaný do Jupyter Notebooku
https://www.root.cz/clanky/interpret-programovaciho-jazyka-clojure-integrovany-do-jupyter-notebooku/ - Babashka: interpret Clojure určený pro rychlé spouštění utilit z příkazového řádku
https://www.root.cz/clanky/babashka-interpret-clojure-urceny-pro-rychle-spousteni-utilit-z-prikazoveho-radku/ - Pokročilý streaming založený na Apache Kafce, jazyku Clojure a knihovně Jackdaw
https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-apache-kafce-jazyku-clojure-a-knihovne-jackdaw/ - Pokročilý streaming založený na Apache Kafce, jazyku Clojure a knihovně Jackdaw (2. část)
https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-apache-kafce-jazyku-clojure-a-knihovne-jackdaw-2-cast/ - Pokročilý streaming založený na projektu Apache Kafka, jazyku Clojure a knihovně Jackdaw (streamy a kolony)
https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-projektu-apache-kafka-jazyku-clojure-a-knihovne-jackdaw-streamy-a-kolony/ - Řídicí struktury využitelné v programovacím jazyku Clojure
https://www.root.cz/clanky/ridici-struktury-vyuzitelne-v-programovacim-jazyku-clojure/ - Řídicí struktury využitelné v programovacím jazyku Clojure (dokončení)
https://www.root.cz/clanky/ridici-struktury-vyuzitelne-v-programovacim-jazyku-clojure-dokonceni/ - Formát EDN: extensible data notation
https://www.root.cz/clanky/format-edn-extensible-data-notation/ - Formát EDN: extensible data notation (dokončení)
https://www.root.cz/clanky/format-edn-extensible-data-notation-dokonceni/ - Čtyři různé podoby datové struktury map v programovacím jazyku Clojure
https://www.root.cz/clanky/ctyri-ruzne-podoby-datove-struktury-map-v-programovacim-jazyku-clojure/ - Programová tvorba diagramů v jazyku Clojure s využitím knihovny Rhizome
https://www.root.cz/clanky/programova-tvorba-diagramu-v-jazyku-clojure-s-vyuzitim-knihovny-rhizome/ - Využití Redisu z jazyka Clojure pomocí knihovny Carmine
https://www.root.cz/clanky/vyuziti-redisu-z-jazyka-clojure-pomoci-knihovny-carmine/ - Využití Redisu z jazyka Clojure pomocí knihovny Carmine (dokončení)
https://www.root.cz/clanky/vyuziti-redisu-z-jazyka-clojure-pomoci-knihovny-carmine-dokonceni/
20. Odkazy na Internetu
- functools — Higher-order functions and operations on callable objects
https://docs.python.org/3/library/functools.html - Functional Programming HOWTO
https://docs.python.org/3/howto/functional.html - Functional Programming in Python: When and How to Use It
https://realpython.com/python-functional-programming/ - Functional Programming With Python
https://realpython.com/learning-paths/functional-programming/ - Awesome Functional Python
https://github.com/sfermigier/awesome-functional-python - Currying
https://en.wikipedia.org/wiki/Currying - Currying in Python – A Beginner’s Introduction
https://www.askpython.com/python/examples/currying-in-python - Fundamental Concepts in Programming Languages
https://en.wikipedia.org/wiki/Fundamental_Concepts_in_Programming_Languages - When should I use function currying?
https://stackoverflow.com/questions/24881604/when-should-i-use-function-currying - Toolz
https://github.com/pytoolz/toolz/tree/master - Coconut: funkcionální jazyk s pattern matchingem kompatibilní s Pythonem
https://www.root.cz/clanky/coconut-funkcionalni-jazyk-s-pattern-matchingem-kompatibilni-s-pythonem/ - A HITCHHIKER'S GUIDE TO functools
https://ep2021.europython.eu/media/conference/slides/a-hitchhikers-guide-to-functools.pdf - Coconut aneb funkcionální nadstavba nad Pythonem (2.část)
https://www.root.cz/clanky/coconut-aneb-funkcionalni-nadstavba-nad-pythonem-2-cast/ - Knihovny pro zpracování posloupností (sekvencí) v Pythonu
https://www.root.cz/clanky/knihovny-pro-zpracovani-posloupnosti-sekvenci-v-pythonu/ - clj – repositář s knihovnou
https://github.com/bfontaine/clj - clj 0.1.0 – stránka na PyPi
https://pypi.python.org/pypi/clj/0.1.0 - Coconut: Simple, elegant, Pythonic functional programming
http://coconut-lang.org/ - coconut (Python package index)
https://pypi.python.org/pypi/coconut/ - 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 - Object-Oriented Programming — The Trillion Dollar Disaster
https://betterprogramming.pub/object-oriented-programming-the-trillion-dollar-disaster-92a4b666c7c7 - Goodbye, Object Oriented Programming
https://cscalfani.medium.com/goodbye-object-oriented-programming-a59cda4c0e53 - So You Want to be a Functional Programmer (Part 1)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-1–1f15e387e536 - So You Want to be a Functional Programmer (Part 2)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-2–7005682cec4a - So You Want to be a Functional Programmer (Part 3)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-3–1b0fd14eb1a7 - So You Want to be a Functional Programmer (Part 4)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-4–18fbe3ea9e49 - So You Want to be a Functional Programmer (Part 5)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-5-c70adc9cf56a - So You Want to be a Functional Programmer (Part 6)
https://cscalfani.medium.com/so-you-want-to-be-a-functional-programmer-part-6-db502830403 - Why Programmers Need Limits
https://cscalfani.medium.com/why-programmers-need-limits-3d96e1a0a6db - Infographic showing code complexity vs developer experience
https://twitter.com/rossipedia/status/1580639227313676288 - Python's reduce(): From Functional to Pythonic Style
https://realpython.com/python-reduce-function/ - What is the problem with reduce()?
https://stackoverflow.com/questions/181543/what-is-the-problem-with-reduce - The fate of reduce() in Python 3000
https://www.artima.com/weblogs/viewpost.jsp?thread=98196 - Reading 16: Map, Filter, Reduce
http://web.mit.edu/6.031/www/sp22/classes/16-map-filter-reduce/ - Currying
https://sw-samuraj.cz/2011/02/currying/ - Používání funkcí v F#
https://docs.microsoft.com/cs-cz/dotnet/fsharp/tutorials/using-functions - Funkce vyššího řádu
http://naucte-se.haskell.cz/funkce-vyssiho-radu - Currying (Wikipedia)
https://en.wikipedia.org/wiki/Currying - Currying (Haskell wiki)
https://wiki.haskell.org/Currying - Haskell Curry
https://en.wikipedia.org/wiki/Haskell_Curry - Moses Schönfinkel
https://en.wikipedia.org/wiki/Moses_Sch%C3%B6nfinkel - ML – funkcionální jazyk s revolučním typovým systémem
https://www.root.cz/clanky/ml-funkcionalni-jazyk-s-revolucnim-typovym-systemem/ - Funkce a typový systém programovacího jazyka ML
https://www.root.cz/clanky/funkce-a-typovy-system-programovaciho-jazyka-ml/ - Curryfikace (currying), výjimky a vlastní operátory v jazyku ML
https://www.root.cz/clanky/curryfikace-currying-vyjimky-a-vlastni-operatory-v-jazyku-ml/ - Primer on Python Decorators
https://realpython.com/primer-on-python-decorators/ - Python Decorators
https://www.programiz.com/python-programming/decorator - PythonDecorators (Python Wiki)
https://wiki.python.org/moin/PythonDecorators - Funcy na GitHubu
https://github.com/suor/funcy/ - Welcome to funcy documentation!
https://funcy.readthedocs.io/en/stable/ - Funcy cheatsheet
https://funcy.readthedocs.io/en/stable/cheatsheet.html - PyToolz API Documentation
https://toolz.readthedocs.io/en/latest/index.html - Toolz (PyToolz) na GitHubu
https://github.com/pytoolz/toolz - Fn.py: enjoy FP in Python
https://github.com/kachayev/fn.py - Funcy na PyPi
https://pypi.org/project/funcy/ - Underscore aneb další knihovna pro funkcionální programování v JavaScriptu
https://www.root.cz/clanky/underscore-aneb-dalsi-knihovna-pro-funkcionalni-programovani-v-javascriptu/ - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Awesome functional Python
https://github.com/sfermigier/awesome-functional-python