Syntaktický cukr

Jako syntaktický cukr (syntactic sugar) je označení syntaktických konstrukcí jazyka, které by šli zapsat běžnou syntaxí, ale syntaktický cukr je další, obvykle kratší a přehlednější formou zápisu.

Zjednodušený cyklus (vytváření seznamů)

Uvažujte následující příklad inicializace seznamu:

>>> squares = []
>>> for x in range(10):
...     squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Nešlo by to nějak stručněji? Šlo:

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Tento zkrácený zápis může být i vnoření cyklus a mít na konci podmínku if. Pokud není podmínka if splněna, do výsledného seznamu (listu …) se hodnota/výraz nedostane.

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y)]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Další příklad transponuje matici (resp. seznam seznamů).

>>> matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

Obdobně to jde i s typem set:

>>> {x for x in 'abracadabra' if x not in 'abc'}
{'r', 'd'}

A nebo se slovníkem:

>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

A nebo s n-ticí:

>>> (x**2 for x in range(10))
<generator object <genexpr> at 0xb7303144>

A ejhle, ona se nevytvořila n-tice, ale jakýsi generátor. Vzpomeňte si na funkci (x)range(), která vracela typ 'range'. Zde to má význam stejný – šetří se paměť počítače.
Vytvoření generátoru dává vcelku u neměnitelné n-tice smysl (narozdíl od měnitelného seznamu).

Bacha na to, že do tohoto generátoru nelze přistupovat pomocí indexů. Pokud byste něco takového potřebovali, není nic snazšího než převést generátor na n-tici:

>>> g = (x**2 for x in range(10))
>>> n = list(g)
>>> n[4]
16
>>> g[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'generator' object is not subscriptable

Lambda funkce

Klíčové slovo lambda se používá pro vytvoření nepojmenovaných funkcí. Hodí se v případech, kde chcete vytvořit funkci „na jedno použití“. Tedy tam, kde by jste normálně definovali funkci (pomocí def), pak ji jednou použili a zase smazali.

Tělo lambda funkce je omezené na jeden výraz. Takže jako lambda funkce není možné psát nic extra složitého.

Za klíčové slovo lambda se píší jména argumentů (nejsou v závorce), pak dvojtečka a pak výraz, který je zároveň tělem i návratovou hodnotou lambda funkce.

>>> lambda x:  x + 1
<function <lambda> at 0xb72fd8b4>
>>> def inc(x):
...     return x + 1
...
>>> inc(5)
6
>>> inc = lambda x: x + 1
>>> inc(5)
6

Funkce vytvořené uvnitř jiné funkce mají přístup k lokálním proměnným funkce, která je vytváří. Toho se dá využít. Pokud funkci vrátíte jako návratovou hodnotu, lokální proměnné vytvářející funkce budou stále s vytvořenou funkcí svázány (funguje to podobně jako v JavaScriptu, jestli to znáte).

>>> def uzavorkovavac(start, end):
...     return lambda *hodnoty: "{}{}{}".format(start, " ".join(hodnoty), end)
...
>>> u = uzavorkovavac('{', '}')
>>> u('a', 'b', 'c')
'{a b c}'
>>> h1 = uzavorkovavac('<h1>', '</h1>') # nove volani fce uzavorkovavac() -> nove lokalni promenne
>>> h1('zdar')
'<h1>zdar</h1>'
>>> u('zdar')          # porad pristupuje k puvodnim lokalnim promennym start a end
'{zdar}'
>>>

Zdůrazňuji, že tato vlastnost s uchováváním odkazů na lokální proměnné nadřazené funkce se netýkají jen lambda funkcí, ale i funkcí definovaných pomocí def (definovaných uvnitř jiné funkce). Použití lambda je opravdu jen syntaktický cukr.

Komentář Hlášení chyby
Created: 15.5.2013
Last updated: 30.8.2015