[python] jak 'odekorovat' property?

Radek Kanovsky rk na dat.cz
Pondělí Listopad 6 10:37:49 CET 2006


On Sun, Nov 05, 2006 at 09:13:52PM +0100, david wrote:

> Chtel jsem pouzit dekorator na funkci, ktera je pouzita pri definici
> property. A to samo o sobe probehne tak jak ma(aspon myslim ;-) )
> Problem je potom to, ze property potom nepouziva tu novou funkci.
> Takze se omlouvam za nepresnou formulaci: asi vazne nezalezi na
> tom, jestli je property readonly nebo ne, problem je v tom, jak
> predefinovat/updatovat/opravit existujici property tak, aby vyuzivala
> zmenenou funkci. Nevim jestli jsem to napsal vystizne: nejlepsi bude
> asi priklad:
>
> def Decorator(old):
>     def novafunkce(*a,**kw):
>         print 'treba logovani:',
>         old_result=old(*a,**kw)
>         return old_result
>     return novafunkce
> class Example(object):
>     def __init__(self,desc):
>         self._description=desc
>     def hello(self):
>         print "hello world"
>     def getdescription(self):
>         print "property funkce",
>         return self._description
>     description=property(getdescription)
> 
> e=Example("POPIS")
> 
> e.hello()
> print e.getdescription()
> print e.description
> 
> e.hello=Decorator(e.hello)
> e.getdescription=Decorator(e.getdescription)
> 
> e.hello()
> print e.getdescription()
> print e.description #nevola novou funkci!

Z meho pohledu je tu nekolik chyb. 

1. Nejzasadnejsi chybu vidim v zameru predefinovat chovani property
v existujici tride. Bezne se to dela v potomku dane tridy, v kterem
chovani zmenim. Pokud budete menit property u tridy za behu, stane
se asi program nesrozumitelnym a vubec pokud mate tu potrebu, asi je
neco spatne v navrhu algoritmu. Porad neni jasne, jestli chcete zmenit
property pro celou tridu nebo jenom pro konkretni instanci teto tridy.
Zkuste spis napsat, proc to vlastne potrebujete. Mozna podobny problem
nekdo resil a vi, jak na to elegantneji.

2. Property je instance, ktera ma odkaz na get metodu getdescription
ulozenu v sobe v read-only atributu fget (staticky). Pokud provedete
pozdeji jakoukoliv zmenu ve tride nebo instanci, property se o tom
nijak nedozvi, jeji atribut fget zustane nedotcen. Pokud dekoruju
pozdeji funkci getdescription, vytvorim tim pouze novou instanci nejake
funkce, ale v property zustane porad ulozena reference na puvodni funkci
getdescription. Pokud by mela property brat ohled na zmeny ve tride,
musi se pouzit neprima get metoda napr.:

    class Example(object):
        def getdescription(self):
            .....
        description = property(lambda self: self.getdescription())

Tim se zajisti, ze pri kazdem pristupu k description se bude metoda
getdescription hledat ve tride a jejich potomcich dynamicky.

Radek Kaňovský


Další informace o konferenci Python