dinamically altering a function

Bengt Richter bokr at oz.net
Sun Mar 13 01:23:32 EST 2005


On Sat, 12 Mar 2005 23:09:58 -0400, vegetax <vegeta.z at gmail.com> wrote:

>Bengt Richter wrote:
[...]
>> 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
>
Maybe this implements what you are asking for?

----< vegetax.py >-------------------------
from ut.presets import presets

class generateObject(object):
    def dispose(self): print 'disposing of %r: %r' %(self, vars(self))

def dec(func):
   def getfun(f): return func  # fake decorator to pass func to presets
   def wrapper(*arg,**kw):
      obj = kw.get('obj',None)
      isSuplied = 1
      if not obj :
         obj = generateObject()
         isSuplied = 0
      else:
          del kw['obj'] # don't pass unexpected kwarg to func
      #<< BIND OBJ TO THE FUNCTION LOCAL NAMESPACE >>
      @presets(obj=obj) # per comment above
      @getfun
      def funcalias(): pass # just for a local name to bind
      res = funcalias(*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.
if __name__ == '__main__':
    @dec
    def fun1(a,b) : obj.result = a + b; return obj, vars(obj)
    @dec
    def fun2(c) : obj.result = c * 4; return obj, vars(obj)
    o, v = fun1(111, 222) # bind obj to show that new obj is generated on next call
    print o, v
    print fun2(1111)
    print 'supplying obj to fun2:', fun2(2222, obj=generateObject()) # supplied
    print 'both ways:', (fun2(1111), fun2(2222, obj=generateObject()))
-------------------------------------------

[22:21] C:\pywk\clp>py24 vegetax.py
disposing of <__main__.generateObject object at 0x02EF9F0C>: {'result': 333}
<__main__.generateObject object at 0x02EF9F0C> {'result': 333}
disposing of <__main__.generateObject object at 0x02EF33CC>: {'result': 4444}
(<__main__.generateObject object at 0x02EF33CC>, {'result': 4444})
supplying obj to fun2: (<__main__.generateObject object at 0x02EF33CC>, {'result': 8888})
both ways: disposing of <__main__.generateObject object at 0x02EF33CC>: {'result': 4444}
((<__main__.generateObject object at 0x02EF33CC>, {'result': 4444}), (<__main__.generateObject o
bject at 0x02EF316C>, {'result': 8888}))


Regards,
Bengt Richter



More information about the Python-list mailing list