Dotaz:

> > Byl by tady někdo, kdo by mě mohl odkázat na rozumný studijní
> > materiál, podtrhuji rozumný, ze kterého bych byl schopen pochopit, jak
> > funguje dekorátor který definuju jako třídu.  S dekorátory jako
> > funkcemi jsem se nějak popasoval, tedy aspoň si to myslim, ale u té
> > třídy je to pro mě černá magie.

Odpověď1:

S tými rozumnými materiálmi je to bieda. Hlavne sa mi zdá, že oficiálny Python Tutorial akosi zaostáva. Pri niekoľkonásobnom prečítaní relevantných (a roztrúsených) častí oficiálnej dokumentácie [1], [2], [3] a PEP 318 [4]_ sa to akosi dá pochopiť. Pokúsim sa to vysvetliť nižsie.:

> > Pokud nemá dekorátor parametry, tak se zdá že to nějak chápu.  Do
> > __init__ je předána dekorovaná fuknce a do __call__ jsou pak předávány
> > argumenty té funkce viz:
> >
> > class mydec:
> >     def __init__(self, fce):
> >         self.fce = fce   # Store, we will use it in __call__
> >
> >     def __call__(self, *args, **kwds):
> >         ....pre
> >         result = self.fce(*args, **kwds)
> >         .....post
> >         return result
> >
> > @mydec
> > def myfunc(*args, **kwds):
> >     pass
> >
> > Ale pokud má mít dekorátor parametry, tak jsem sice našel/zkonstruoval
> > kód který se zdá fungovat, ale plně mu nerozumím.
> > Jen tím že chci aby měl dekorátor parametry, se tak radikálně změní
> > kód dekorátoru.
> > Potřeboval bych nějak po lopatě vědět, co se uvnitř děje, protože
> > cítím že ty dekorátory budu určitě používat ještě mnohem divočeji.

Vo všeobecnosti je dekorátor funkcia, ktorá vracia funkciu. V Pythone je dekorátor „niečo, čo sa dá zavolať“ a po zavolaní to vráti tiež „niečo, čo sa dá zavolať“. To „niečo, čo sa dá zavolať“ je akýkoľvek objekt, ktorý má metódu __call__() – čiže funkcia; trieda; inštancia tredy, ktorá definuje __call__(); jedným slovom callable. To prvé callable reprezentuje samotný dekorátor a to druhé callable reprezentuje, v prípade dekorátora bez parametrov, odekorovanú funkciu (čize funkciu, ktorá už je „oblečená“ do dekorátora).

Dekorátor (to, čo je za @) je volaný pri definícii funkcie, teda nie pri jej zavolaní. Pri tomto volaní sa vráti uz spomínané druhé callable, ktoré reprezentuje odekorovanú funkciu (v prípade dekorátora bez parametrov). To je potom volané zakaždým, keď je volaná dekorovaná funkcia (čiže tá, ktorá má nad sebou @).

Dekorátor bez parametrov, je zavolaný s jedným parametrom a tým je dekorovaná funkcia.

Čiže keď zoberieme Tvoj príklad dekorátora bez parametrov, tak mydec je zavolaný pri definícii myfunc() a dostane myfunc ako parameter. Keď zoberieme do úvahy, že mydec je trieda, tak jej zavolanie vlastne znamená vytvorenie inštancie. Táto vzniknutá inštancia má __call__() a teda spĺňa podmnienku, že je callable. Vniknutá inštancia teda reprezentuje odekorovanú myfunc() a jej metóda __call__() je zavolaná pri každom volaní myfunc().

Dekorátor s parametrami, je zavolaný iba s tými parametrami, s ktorými bol nadefinovaný. Čiže nedostane dekorovanú funkciu. Callable, ktoré takýto dekorátor vráti reprezentuje ďalší dekorátor. Tento ďalší dekorátor, je už „normálny“ dekorátor bez parametrov popísaný vyššie. Je zavolaný tiež pri definícii funkcie (hneď za dekorátorom s parametrami, ktorý ho vrátil) a dostane dekorovanú funkciu ako parameter.

Dúfam, že som Ťa ešte viac nepoplietol. ;-)

[1]http://docs.python.org/py3k/glossary.html#term-decorator
[2]http://docs.python.org/py3k/reference/compound_stmts.html#function
[3]http://docs.python.org/py3k/whatsnew/2.4.html?highlight=decorator

Odpověď2:

jenom bych rad doplnil, ze pythoni syntaxe:

@muj_dekorator
   def moje_funkce(*args): pass

je jenom syntakticky cukr a znamena to:

moje_funkce = muj_dekorator(moje_funkce)

z cehoz je mozna mnohem jasnejsi, jak dekorator funguje. alespon mne to tak dava vetsi smysl ;))