dinamically altering a function

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • vegetax

    #1

    dinamically altering a function


    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.




  • Steven Bethard

    #2
    Re: dinamically altering a function

    vegetax wrote:[color=blue]
    > 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.[/color]

    For a byte-code hack that does something similar, see the recent thread:



    It can do something like:

    py> class Object(object):
    .... pass
    ....
    py> @presets.preset s(obj=Object())
    .... def fun(b):
    .... obj.desc = "marked"
    .... obj.b = b
    .... return obj
    ....
    py> fun(1)
    <__main__.Objec t 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

    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__.Objec t 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?

    STeVe

    Comment

    • vegetax

      #3
      Re: dinamically altering a function

      Steven Bethard wrote:
      [color=blue]
      > vegetax wrote:[color=green]
      >> 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.[/color]
      >
      > For a byte-code hack that does something similar, see the recent thread:
      >
      > http://mail.python.org/pipermail/pyt...ch/270324.html
      >
      > It can do something like:
      >
      > py> class Object(object):
      > ... pass
      > ...
      > py> @presets.preset s(obj=Object())
      > ... def fun(b):
      > ... obj.desc = "marked"
      > ... obj.b = b
      > ... return obj
      > ...
      > py> fun(1)
      > <__main__.Objec t 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[/color]

      Interesting hack, but the functions must not share the same object.Maybe i
      could make my version of that decorator,i will check it.
      [color=blue]
      > 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__.Objec t 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?[/color]

      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,function s.

      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.




      Comment

      • Steven Bethard

        #4
        Re: dinamically altering a function

        vegetax wrote:[color=blue]
        > Steven Bethard wrote:[color=green]
        >>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__.Obj ect 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?[/color]
        >
        > 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,function s.
        >
        > 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.[/color]

        If you need to use it as a decorator, you could try something like:

        py> class Object(object):
        .... pass
        ....
        py> class ObjectSupplier( object):
        .... def __init__(self, func):
        .... self.func = func
        .... def __call__(self, *args):
        .... if len(args) == 2:
        .... obj, b = args
        .... elif len(args) == 1:
        .... obj, [b] = Object(), args
        .... else:
        .... raise TypeError
        .... return self.func(obj, b)
        ....
        py> @ObjectSupplier
        .... def fun(obj, b):
        .... obj.desc = "marked"
        .... obj.b = b
        .... return obj
        ....
        py> fun(1)
        <__main__.Objec t object at 0x01162910>
        py> fun(1).b
        1
        py> myobject = Object()
        py> fun(myobject, 2)
        <__main__.Objec t object at 0x01162770>
        py> myobject.b
        2

        Basically, ObjectSupplier just guarantees that the function will be
        called with an initialized Object argument if one isn't supplied. Note
        that your functions must be declared with the initial argument now though.

        STeVe

        P.S. Making ObjectSupplier general enough to work with any number of
        arguments is left as an exercise to the reader. ;)

        Comment

        • Jeremy Bowers

          #5
          Re: dinamically altering a function

          > What i want is to declare in the decorator some code that is common to all[color=blue]
          > 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.[/color]

          This sounds like a call for a Pythonic varient on the Template pattern:

          class Root(object):
          def __init__(self):
          self.dataChunk = 22 # or whatever

          class Child(Root):
          def __call__(self):
          print self.dataChunk
          [color=blue][color=green][color=darkred]
          >>> c = Child()
          >>> c()[/color][/color][/color]
          22


          Don't be put off by the "OO"-ness here, it acts just like a function
          thanks to __call__, and behind the scenes you get full OO support for your
          functions.

          I strongly suspect this is the best solution to your problem, not a
          decorator. Note whatever you are doing to create the functions can be done
          in other ways, especially note that "class" statements are executed, not
          declarations, for instance:
          [color=blue][color=green][color=darkred]
          >>> import operator
          >>> class Root(object):[/color][/color][/color]
          .... def __init__(self):
          .... self.op1 = 22
          .... self.op2 = 44
          ....[color=blue][color=green][color=darkred]
          >>> funcs = []
          >>> for op in operator.add, operator.sub, operator.pow:[/color][/color][/color]
          .... def newfunc(self, basefunc = op):
          .... print basefunc(self.o p1, self.op2)
          .... class New(Root):
          .... __call__ = newfunc
          .... funcs.append(Ne w)
          ....[color=blue][color=green][color=darkred]
          >>> funcs # show the classes[/color][/color][/color]
          [<class '__main__.New'> , <class '__main__.New'> , <class '__main__.New'>][color=blue][color=green][color=darkred]
          >>> [x() for x in funcs] # show the new "functions"[/color][/color][/color]
          [<__main__.New object at 0xb7e78bcc>, <__main__.New object at 0xb7e78e4c>, <__ma
          in__.New object at 0xb7e78ecc>][color=blue][color=green][color=darkred]
          >>> [x()() for x in funcs] # call each of the functions, note no return[/color][/color][/color]
          66
          -22
          116572995441436 549620289361494 791139391860487 905922101805056
          [None, None, None]

          Upshot is, with a bit of creativity this can do whatever you want, in
          conjection with dynamically-created classes, no bytecode hacks, no really
          weird decorators, just standard OO and __call__.

          Comment

          • Bengt Richter

            #6
            Re: dinamically altering a function

            On Sat, 12 Mar 2005 18:19:36 -0400, vegetax <vegeta.z@gmail .com> wrote:
            [color=blue]
            >Steven Bethard wrote:
            >[color=green]
            >> vegetax wrote:[color=darkred]
            >>> 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.[/color]
            >>
            >> For a byte-code hack that does something similar, see the recent thread:
            >>
            >> http://mail.python.org/pipermail/pyt...ch/270324.html
            >>
            >> It can do something like:
            >>
            >> py> class Object(object):
            >> ... pass
            >> ...
            >> py> @presets.preset s(obj=Object())
            >> ... def fun(b):
            >> ... obj.desc = "marked"
            >> ... obj.b = b
            >> ... return obj
            >> ...
            >> py> fun(1)
            >> <__main__.Objec t 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[/color]
            >
            >Interesting hack, but the functions must not share the same object.Maybe i
            >could make my version of that decorator,i will check it.[/color]
            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

            [color=blue][color=green][color=darkred]
            >>> def mkfun(obj=None) :[/color][/color][/color]
            ... if obj is None: obj = Obj()
            ... def fun(b):
            ... obj.desc = 'marked'
            ... obj.b = b
            ... return obj
            ... return fun
            ...[color=blue][color=green][color=darkred]
            >>> fun = mkfun()[/color][/color][/color]
            Traceback (most recent call last):
            File "<stdin>", line 1, in ?
            File "<stdin>", line 2, in mkfun
            NameError: global name 'Obj' is not defined

            oops
            [color=blue][color=green][color=darkred]
            >>> class Obj(object): pass[/color][/color][/color]
            ...[color=blue][color=green][color=darkred]
            >>> fun = mkfun()
            >>> fun2 = mkfun()
            >>> fun(1)[/color][/color][/color]
            <__main__.Obj object at 0x02EF15CC>[color=blue][color=green][color=darkred]
            >>> fun(1).b[/color][/color][/color]
            1[color=blue][color=green][color=darkred]
            >>> fun(2).b[/color][/color][/color]
            2[color=blue][color=green][color=darkred]
            >>> fun2(3)[/color][/color][/color]
            <__main__.Obj object at 0x02EF162C>[color=blue][color=green][color=darkred]
            >>> fun2(3).b[/color][/color][/color]
            3[color=blue][color=green][color=darkred]
            >>> fun(1) is fun2(2)[/color][/color][/color]
            False[color=blue][color=green][color=darkred]
            >>> fun(1) is fun(2)[/color][/color][/color]
            True

            The code of the function the factory produces is:
            [color=blue][color=green][color=darkred]
            >>> dis.dis(mkfun() )[/color][/color][/color]
            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:
            [color=blue][color=green][color=darkred]
            >>> from ut.presets import presets
            >>> def mkfun(obj=None) :[/color][/color][/color]
            ... if obj is None: obj = Obj()
            ... @presets(obj=ob j)
            ... def fun(b):
            ... obj.desc = 'marked'
            ... obj.b = b
            ... return obj
            ... return fun
            ...[color=blue][color=green][color=darkred]
            >>> dis.dis(mkfun() )[/color][/color][/color]
            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.
            [color=blue]
            >[color=green]
            >> 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__.Objec t 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?[/color][/color]
            Yes, that is a good question ;-)
            [color=blue]
            >
            >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,function s.
            >
            >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.[/color]
            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

            Comment

            • vegetax

              #7
              Re: dinamically altering a function

              Bengt Richter wrote:
              [color=blue]
              > On Sat, 12 Mar 2005 18:19:36 -0400, vegetax <vegeta.z@gmail .com> wrote:
              >[color=green]
              >>Steven Bethard wrote:
              >>[color=darkred]
              >>> 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/pyt...ch/270324.html
              >>>
              >>> It can do something like:
              >>>
              >>> py> class Object(object):
              >>> ... pass
              >>> ...
              >>> py> @presets.preset s(obj=Object())
              >>> ... def fun(b):
              >>> ... obj.desc = "marked"
              >>> ... obj.b = b
              >>> ... return obj
              >>> ...
              >>> py> fun(1)
              >>> <__main__.Objec t 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[/color]
              >>
              >>Interesting hack, but the functions must not share the same object.Maybe i
              >>could make my version of that decorator,i will check it.[/color]
              > 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
              >
              >[color=green][color=darkred]
              > >>> def mkfun(obj=None) :[/color][/color]
              > ... if obj is None: obj = Obj()
              > ... def fun(b):
              > ... obj.desc = 'marked'
              > ... obj.b = b
              > ... return obj
              > ... return fun
              > ...[color=green][color=darkred]
              > >>> fun = mkfun()[/color][/color]
              > Traceback (most recent call last):
              > File "<stdin>", line 1, in ?
              > File "<stdin>", line 2, in mkfun
              > NameError: global name 'Obj' is not defined
              >
              > oops
              >[color=green][color=darkred]
              > >>> class Obj(object): pass[/color][/color]
              > ...[color=green][color=darkred]
              > >>> fun = mkfun()
              > >>> fun2 = mkfun()
              > >>> fun(1)[/color][/color]
              > <__main__.Obj object at 0x02EF15CC>[color=green][color=darkred]
              > >>> fun(1).b[/color][/color]
              > 1[color=green][color=darkred]
              > >>> fun(2).b[/color][/color]
              > 2[color=green][color=darkred]
              > >>> fun2(3)[/color][/color]
              > <__main__.Obj object at 0x02EF162C>[color=green][color=darkred]
              > >>> fun2(3).b[/color][/color]
              > 3[color=green][color=darkred]
              > >>> fun(1) is fun2(2)[/color][/color]
              > False[color=green][color=darkred]
              > >>> fun(1) is fun(2)[/color][/color]
              > True
              >
              > The code of the function the factory produces is:
              >[color=green][color=darkred]
              > >>> dis.dis(mkfun() )[/color][/color]
              > 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:
              >[color=green][color=darkred]
              > >>> from ut.presets import presets
              > >>> def mkfun(obj=None) :[/color][/color]
              > ... if obj is None: obj = Obj()
              > ... @presets(obj=ob j)
              > ... def fun(b):
              > ... obj.desc = 'marked'
              > ... obj.b = b
              > ... return obj
              > ... return fun
              > ...[color=green][color=darkred]
              > >>> dis.dis(mkfun() )[/color][/color]
              > 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.
              >[color=green]
              >>[color=darkred]
              >>> 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__.Objec t 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?[/color][/color]
              > Yes, that is a good question ;-)
              >[color=green]
              >>
              >>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,function s.
              >>
              >>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.[/color]
              > 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[/color]

              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',No ne)
              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',No ne)
              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



              Comment

              • Bengt Richter

                #8
                Re: dinamically altering a function

                On Sat, 12 Mar 2005 23:09:58 -0400, vegetax <vegeta.z@gmail .com> wrote:
                [color=blue]
                >Bengt Richter wrote:[/color]
                [...][color=blue][color=green]
                >> Please pretend things worked the way you want, and post an example. Maybe
                >> we can make it work.
                >>
                >> Regards,
                >> Bengt Richter[/color]
                >
                >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',No ne)
                > 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',No ne)
                > 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
                >[/color]
                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',No ne)
                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=ob j) # 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=generateObj ect()) # supplied
                print 'both ways:', (fun2(1111), fun2(2222, obj=generateObj ect()))
                -------------------------------------------

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


                Regards,
                Bengt Richter

                Comment

                Working...