Bengt Richter wrote: > On Sat, 12 Mar 2005 18:19:36 -0400, vegetax <[EMAIL PROTECTED]> wrote: > >>Steven Bethard wrote: >> >>> vegetax wrote: >>>> I i need a decorator that adds a local variable in the function it >>>> decorates, probably related with nested scopes, for example: >>>> >>>> def dec(func): >>>> def wrapper(obj = None): >>>> if not obj : obj = Obj() >>>> <bind obj to func> >>>> return func() >>>> >>>> return wrapper() >>>> >>>> @dec() >>>> def fun(b): >>>> obj.desc = 'marked' >>>> obj.b = b >>>> return obj >>>> >>>> so the call to fun : fun(obj = myobj,'b argument') >>>> or fun('b argument') >>>> >>>> So the function "fun" assumes it has an obj instance and other instance >>>> objects computed by the decorator, this decorator will be like a >>>> generic factory for this kind of functions,which depends on the >>>> decorator to work. >>> >>> For a byte-code hack that does something similar, see the recent thread: >>> >>> http://mail.python.org/pipermail/python-list/2005-March/270324.html >>> >>> It can do something like: >>> >>> py> class Object(object): >>> ... pass >>> ... >>> py> @presets.presets(obj=Object()) >>> ... def fun(b): >>> ... obj.desc = "marked" >>> ... obj.b = b >>> ... return obj >>> ... >>> py> fun(1) >>> <__main__.Object object at 0x01162BD0> >>> py> fun(1).b >>> 1 >>> >>> But note that you then only have a single instance for all calls to the >>> function: >>> >>> py> fun(1) is fun(2) >>> True >> >>Interesting hack, but the functions must not share the same object.Maybe i >>could make my version of that decorator,i will check it. > What do you mean "function_s_" [plural] ? I see only one function named > "fun". An ordinary decorator will only modify that single function, so if > you want more than one function instance, IWT you would want a factory > function that can produce multiple function instances, tailored as you > like. You could use a decorator to modify a template function within the > factory, and return the result. But you might no need a decorator if you > just make your template function refer to stuff passed into the factory, > i.e., as cell variables. > > Will your template function know the names of dynamic things it will use? > If not, what kind of protocol will you use to discover what's available? > If it does know the names (like "obj") then you could just write something > like > > > >>> def mkfun(obj=None): > ... if obj is None: obj = Obj() > ... def fun(b): > ... obj.desc = 'marked' > ... obj.b = b > ... return obj > ... return fun > ... > >>> fun = mkfun() > Traceback (most recent call last): > File "<stdin>", line 1, in ? > File "<stdin>", line 2, in mkfun > NameError: global name 'Obj' is not defined > > oops > > >>> class Obj(object): pass > ... > >>> fun = mkfun() > >>> fun2 = mkfun() > >>> fun(1) > <__main__.Obj object at 0x02EF15CC> > >>> fun(1).b > 1 > >>> fun(2).b > 2 > >>> fun2(3) > <__main__.Obj object at 0x02EF162C> > >>> fun2(3).b > 3 > >>> fun(1) is fun2(2) > False > >>> fun(1) is fun(2) > True > > The code of the function the factory produces is: > > >>> dis.dis(mkfun()) > 4 0 LOAD_CONST 1 ('marked') > 3 LOAD_DEREF 0 (obj) > 6 STORE_ATTR 1 (desc) > > 5 9 LOAD_FAST 0 (b) > 12 LOAD_DEREF 0 (obj) > 15 STORE_ATTR 2 (b) > > 6 18 LOAD_DEREF 0 (obj) > 21 RETURN_VALUE > > We could use the byte code hack to change the code not to use > LOAD_DEREF cell vars, but preset and use a local variable instead: > > >>> from ut.presets import presets > >>> def mkfun(obj=None): > ... if obj is None: obj = Obj() > ... @presets(obj=obj) > ... def fun(b): > ... obj.desc = 'marked' > ... obj.b = b > ... return obj > ... return fun > ... > >>> dis.dis(mkfun()) > 3 0 LOAD_CONST 2 (<__main__.Obj object at > 0x02EF728C>) > 3 STORE_FAST 1 (obj) > > 5 6 LOAD_CONST 1 ('marked') > 9 LOAD_FAST 1 (obj) > 12 STORE_ATTR 1 (desc) > > 6 15 LOAD_FAST 0 (b) > 18 LOAD_FAST 1 (obj) > 21 STORE_ATTR 2 (b) > > 7 24 LOAD_FAST 1 (obj) > 27 RETURN_VALUE > > Not sure that gains anything significant. > >> >>> Have you considered using OO here? You might find that this is more >>> easily written as: >>> >>> py> class Object(object): >>> ... pass >>> ... >>> py> class fun(object): >>> ... def __new__(self, *args): >>> ... if len(args) == 2: >>> ... obj, b = args >>> ... elif len(args) == 1: >>> ... obj, [b] = Object(), args >>> ... else: >>> ... raise TypeError >>> ... obj.desc = "marked" >>> ... obj.b = b >>> ... return obj >>> ... >>> py> myobj = Object() >>> py> fun(myobj, 2) >>> <__main__.Object object at 0x01162E30> >>> py> myobj.b >>> 2 >>> py> obj = fun(1) >>> py> obj.b >>> 1 >>> >>> This doesn't use any bytecode hacks, but I'm still not certain it's >>> really the way to go. What is it you're trying to write this way? > Yes, that is a good question ;-) > >> >>OO doesnt work here,i have factored to classes with inheritance but it >>looks clumsy and it is clumsy to use, this things are in nature,functions. >> >>What i want is to declare in the decorator some code that is common to all >>these functions, so the functions assume that the decorator will be there >>and wont need to duplicate the code provided by it, and the functions are >>not known ahead of time, it has to be dynamic. > Still not sure what you mean by "the functions are not known ahead of > time." > > Please pretend things worked the way you want, and post an example. Maybe > we can make it work. > > Regards, > Bengt Richter
Ok , the complete use case is : def fun1(a,b,obj = None): isSuplied = 1 if not obj : obj = generateObject() isSuplied = 0 <do something with obj> if not isSuplied : obj.dispose() def fun2(c,obj = None): isSuplied = 1 if not obj : obj = generateObject() isSuplied = 0 <do something else with obj> if not isSuplied : obj.dispose() So , maybe i will need to define fun3 later,i dont know , but fun3 also will work with "obj". So the thing is to try to factorize the code,so that it is in the decorator: def dec(func): def wrapper(*arg,**kw): obj = kw.get('obj',None) isSuplied = 1 if not obj : obj = generateObject() kw['obj'] = obj isSuplied = 0 res = func(*arg,**kw) if not isSuplied : obj.dispose() return res return wrapper so the previous function declarations, will look like: @dec def fun1(a,b,obj = None): <do something with obj> @dec def fun2(c,obj = None): <do something with obj> but i have to define obj = None in each function,but the functions should know they will have an obj instance available, so the byte code hack would be : def dec(func): def wrapper(*arg,**kw): obj = kw.get('obj',None) isSuplied = 1 if not obj : obj = generateObject() isSuplied = 0 << BIND OBJ TO THE FUNCTION LOCAL NAMESPACE >> res = func(*arg,**kw) if not isSuplied : obj.dispose() return res return wrapper so the functions knowing they will be altered(added an instance of obj),they will just need to define their own arguments only. @dec fun1(a,b) : obj.result = a + b @dec fun2(c) : obj.result = c * 4 So the duplication would be removed. But i realized the best aproach,is a callable class that provides that infrastructure, or not? =P -- http://mail.python.org/mailman/listinfo/python-list