[python] Deferred output
Petr Messner
petr.messner na gmail.com
Čtvrtek Únor 11 03:22:47 CET 2010
(odpověď je dole)
On 11.2.2010, at 2:35, matesfila wrote:
>
> Zdravím,
>
> mám taký trochu algoritmický problém!
>
> Na adrese http://code.activestate.com/recipes/576961/ som sa dopátral k pre mňa dosť záhadnej algoritmickej konštrukcii, ktorú tam autor nazýva zhruba ako deferred output.
>
> Ide o tento algoritmus:
>
> def fibonacci():
> """ Funkcia na počítanie Fibonachiho čísiel """
> def deferred_output():
> for i in output:
> yield i
>
> result, c1, c2 = tee(deferred_output(), 3)
> paired = map(add, c1, islice(c2, 1, None))
> output = chain([0, 1], paired)
> return result
>
> #príklad použitia funkcie:
> print(list(islice(fibonacci(), 50)))
>
> Sú mi jasné metódy ako list, islice, chain a myslím, že aj map, tee a využitie generátora.
>
> Ale ako je možné, že v generátore sa využíva premenná, ktoré ešte nebola nikde definovaná? !!! Pravdepodobne sa tam nejako využíva vlastnosť generátora, ktorý premennnú 'output' využije vlastne až keď sa vyvolá next() na generátore a v tej dobe vlastne premenná už asi existuje... ale neviem, jaksik tie myšlienky tam využité neviem definovať a uchopiť :-)
>
Ano, výraz deferred_output() nespustí kód uvnitř funkce deferred_output; protože je to generátor (to se pozná už při parsování kódu), vrátí se iterátor a teprve při procházení iterátoru se spustí kód uvnitř deferred_output. A v tom okamžiku už "volná proměnná" output existuje.
Takovéto techniky bych rozhodně neoznačil za běžně používané v Pythonu.
Zrovna tento kód mi nefungoval, ale asi tuším, co to dělá - deferred_output() představuje nějaký iterátor; vytvoří se "nad ním" tři nezávislé iterátory, jeden z nich se vrátí, další dva slouží ke sčítání (posledního a předposledního prvku), které je vyjádřeno iterátorem paired, a ten se (spolu s počátečními prvky - 0 a 1) vloží do deferred_output.
Takže co se děje, když máš iterátor fibonacci() a zavoláš na něj next(): to, co máš, je vlastně iterátor z tee, to tee uchovává potřebnou historii (předposlední a poslední prvek, diky tomu, že další dva iterátory vzniklé z tee() právě na tyto prvky ukazují). Když chceš další prvek z result, vezme se další prvek z iterátoru vzniklého z map(), který je zadán jako součet hodnoty toho druhého a třetího iterátoru z tee(). Tedy součet předposledního a posledního čísla. Tento součet se zároveň uloží (funkcionalita tee). Asi jsem to popsal trochu zmateně, je prostě nutné se do toho kódu delší chvíli dívat :)
PM
Další informace o konferenci Python