Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: honza 28. 08. 2015, 11:09:28

Název: Python: decorator, jak předat instance-member proměnnou at runtime?
Přispěvatel: honza 28. 08. 2015, 11:09:28
Dobry den,

mam dekorator @cache(size=xxx), chtel bych jeho hodnotu nastavovat az podle parametru tridy ve ktere je pouzit, ale nedari se mi pristoupt k ani jednomu z instance, class, static, global promennych. Asi lepsi ukazka kyzeneho stavu v (pseudo) pythonu:

Kód: [Vybrat]
# dekorator
def cache(f):
  ...

class A():
  def __init__(self, cacheSize=0):
    self.cacheSize = cacheSize

  @cache(maxsize=self.cacheSize) # tohle nejde..hledal jsem vsemozne pristupy
  def long_method(self,x):
    ...

# pouziti
a=A(5)
a.long_method(3)


dekuji moc za vysvetleni!
Název: Re:Python: decorator, jak předat instance-member proměnnou at runtime?
Přispěvatel: somemonster 28. 08. 2015, 11:50:22
Ten dekorator je executovany pri vytvoreni classy a vtedy self neexistuje, self vznika pri vytvoreni instancie. Co mozes urobit je v inner funkcii  ten parameter vytiahnut z funkcie long_method kedze ta pasne dekoratoru aj svoj self.
Název: Re:Python: decorator, jak předat instance-member proměnnou at runtime?
Přispěvatel: Ondrej 28. 08. 2015, 12:40:02
Zdravím,

Toto jde udělat vcelku jednoduše:

from functools import wraps

def cache(f):
    print "Dekoruji."
    @wraps(f)
    def decorated_func(self, *args, **kwargs):
        print self # tady je možné dělat se self cokoliv
        return f(self, *args, **kwargs)
    return decorated_func
Název: Re:Python: decorator, jak předat instance-member proměnnou at runtime?
Přispěvatel: honza 28. 08. 2015, 13:22:23
Dekuji za odpovedi,
muj problem je, ze to co chci wrappnout, abych mohl predat self.xxx parametr neni moje funkce, ale uz dekorator, ktery vyzaduje jeden argument.
tedy:

Kód: [Vybrat]
# orig wrapper, ktery nemuzu menit (c++ binding), pouziva se takto:
@origcache(maxsize=3)
def long_foo(n):
  pass

# muj cil: vytvorit @mycache ktery precte self.cacheSize z contextu sve instance?
# a bude pritom volat @origcache
class A():
  def __init__(cacheSize):
    self.cacheSize = cacheSize

  @mycache
  def long_foo(n):
    pass

Z Vasich odpovedi chapu proc to nefunguje, ale neumim si priohnout @wraps tak, aby mi opravovalo dekorator. Nasel jsem neco o dekoratorech/descriptorech ...ale v tom se uprimne moc nevyznam.

Diky
Název: Re:Python: decorator, jak předat instance-member proměnnou at runtime?
Přispěvatel: matous 28. 08. 2015, 16:09:53
Koukni se na https://wiki.python.org/moin/PythonDecoratorLibrary (https://wiki.python.org/moin/PythonDecoratorLibrary)
Je tam Memoize. To je velice podobné tomu co chceš.
Název: Re:Python: decorator, jak předat instance-member proměnnou at runtime?
Přispěvatel: honza 28. 08. 2015, 17:40:51
Memoize znam, to je pouze implementace cache, tu uz mam. Me jde o to, jak dekoratoru predat argument ze self.neco
Název: Re:Python: decorator, jak předat instance-member proměnnou at runtime?
Přispěvatel: pokus 28. 08. 2015, 20:47:09
?

Kód: [Vybrat]
def origcache(f,size=3):
    def g(*args,**kwds):
        #print(*args, **kwds)
        print('Calling decorated function',size)
        return f(*args, **kwds)
    return g


metaCache={}
def cache(f):
    def g(*args,**kwds):
        try:
            return metaCache[(f,args[0])](*args[1:],**kwds)
        except KeyError:
            print("defining")
            newf=origcache(f,size=args[0].s)
            metaCache[(f,args[0])]=newf
            return newf(*args[1:],**kwds)
        else:
            return
    return g


class A():
    def __init__(self):
        self.s=5

    @cache
    def f(x):
        return str(x)+"aa"


a=A()
print(a.f(2))
print(a.f(2))
Název: Re:Python: decorator, jak předat instance-member proměnnou at runtime?
Přispěvatel: Kit 28. 08. 2015, 22:05:40
Zkus to bez cache!