Adding bound methods dynamically...

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

    Adding bound methods dynamically...

    #!/usr/bin/env python

    '''
    I want to dynamically add or replace bound methods in a class. I want
    the modifications to be immediately effective across all instances,
    whether created before or after the class was modified. I need this
    to work for both old ('classic') and new style classes, at both 2.3
    and 2.4. I of course want to avoid side effects, and to make the
    solution as light-weight as possible.

    Question for the experts: Is the solution coded in AddBoundMethod( )
    acceptable to the Pythonian Gods? :) It does seem to work -- tested
    at 2.3.5 (RH Linux) and 2.4.1 (WinXP)

    Is there a more pythonic way that's as straight forward?
    '''

    def AddBoundMethod( cls, name, method ):
    '''
    Dynamically add to the class 'cls' a bound method.

    Invoking this method instantly adds (or overwrites) the
    bound method identified by 'name' with the code contained in
    'method', EVEN FOR PRE-EXISTING INSTANCES OF THE CLASS. The
    'method' parameter should be a non-class function that has 'self'
    as its first parameter.
    '''

    try: types
    except NameError: import types

    #
    # this is the crux of this example, short and sweet...
    #
    exec "%s.%s = types.MethodTyp e( method, None, %s )" \
    % ( cls.__name__, name, cls.__name__ )

    #
    # The remainder (50x longer than the solution!) is test code...
    #

    # one new-style class...
    class NewStyleClass( object ):

    def __init__ ( self, objname ):
    print "Created a NewStyleClass, id %d, %s" % \
    ( id( self ), objname ) self.objname = objname

    def ExistingMethod( self, msg ):
    print "Original ExistingMethod, id %d, %s: '%s'" % \
    ( id( self ), self.objname, msg )

    # one 'classic' style class...
    class OldStyleClass:

    def __init__ ( self, objname ):
    print "Created a OldStyleClass, id %d, %s" % \
    ( id( self ), objname ) self.objname = objname

    def ExistingMethod( self, msg ):
    print "Original ExistingMethod, id %d, %s: '%s'" % \
    ( id( self ), self.objname, msg )

    # two non-class functions that *look* like bound methods in a class;
    # one returns a value, the other just outputs a string...
    def NeverInOriginal Class( self, msg ):
    return "Never in original class, id %d, %s: '%s'" % \
    ( id( self ), self.objname, msg )

    def NewExistingMeth od( self, msg ):
    print "REPLACED ExistingMethod, id %d, %s: '%s'" % \
    ( id( self ), self.objname, msg )

    # a test routine...
    def Test( cls ):

    print "--- %s ----------------------------------------------" % \
    cls.__name__

    print "type of class %s is '%s'" % ( cls.__name__, type( cls ) )

    before_change = cls('instance created before change')

    print "type of object before_change is '%s'" % type(before_cha nge)

    # 'A' shows that we start with an existing method....
    before_change.E xistingMethod( 'A' )

    print "*** Replacing bound method 'ExistingMethod '..."

    AddBoundMethod( cls, "ExistingMethod ", NewExistingMeth od )

    after_change = cls( 'instance created AFTER change' )

    print "type of after_change is '%s'" % type( after_change )

    # 'B' and 'C' show we've replaced an existing method, both on
    # pre-existing instances and instances created after using
    # AddBoundMethod( )
    before_change.E xistingMethod( 'B' )
    after_change.Ex istingMethod( 'C' )

    print "*** Adding new bound method 'AddedMethod'.. ."

    AddBoundMethod( after_change.__ class__, "AddedMetho d",
    NeverInOriginal Class )

    # 'D' and 'E' show we've added a brand new method, both on
    # pre-existing instances and instances created after using
    # AddBoundMethod( )
    print "%s" % before_change.A ddedMethod( 'D' )
    print "%s" % after_change.Ad dedMethod( 'E' )


    if __name__ == '__main__':

    Test( OldStyleClass )
    Test( NewStyleClass )

  • Kevin Little

    #2
    Re: Adding bound methods dynamically... CORRECTED

    #!/usr/bin/env python

    # Sorry... :} cut/paste error fixed...

    '''
    I want to dynamically add or replace bound methods in a class. I want
    the modifications to be immediately effective across all instances,
    whether created before or after the class was modified. I need this
    to work for both old ('classic') and new style classes, at both 2.3
    and 2.4. I of course want to avoid side effects, and to make the
    solution as light-weight as possible.

    Question for the experts: Is the solution coded in AddBoundMethod( )
    acceptable to the Pythonian Gods? :) It does seem to work -- tested
    at 2.3.5 (RH Linux) and 2.4.1 (WinXP)

    Is there a more pythonic way that's as straight forward?
    '''

    def AddBoundMethod( cls, name, method ):
    '''
    Dynamically add to the class 'cls' a bound method.

    Invoking this method instantly adds (or overwrites) the
    bound method identified by 'name' with the code contained in
    'method', EVEN FOR PRE-EXISTING INSTANCES OF THE CLASS. The
    'method' parameter should be a non-class function that has 'self'
    as its first parameter.
    '''

    try: types
    except NameError: import types

    #
    # this is the crux of this example, short and sweet...
    #
    exec "%s.%s = types.MethodTyp e( method, None, %s )" \
    % ( cls.__name__, name, cls.__name__ )

    #
    # The remainder (50x longer than the solution!) is test code...
    #

    # one new-style class...
    class NewStyleClass( object ):

    def __init__ ( self, objname ):
    print "Created a NewStyleClass, id %d, %s" % \
    ( id( self ), objname )
    self.objname = objname

    def ExistingMethod( self, msg ):
    print "Original ExistingMethod, id %d, %s: '%s'" % \
    ( id( self ), self.objname, msg )

    # one 'classic' style class...
    class OldStyleClass:

    def __init__ ( self, objname ):
    print "Created a OldStyleClass, id %d, %s" % \
    ( id( self ), objname )
    self.objname = objname

    def ExistingMethod( self, msg ):
    print "Original ExistingMethod, id %d, %s: '%s'" % \
    ( id( self ), self.objname, msg )

    # two non-class functions that *look* like bound methods in a class;
    # one returns a value, the other just outputs a string...
    def NeverInOriginal Class( self, msg ):
    return "Never in original class, id %d, %s: '%s'" % \
    ( id( self ), self.objname, msg )

    def NewExistingMeth od( self, msg ):
    print "REPLACED ExistingMethod, id %d, %s: '%s'" % \
    ( id( self ), self.objname, msg )

    # a test routine...
    def Test( cls ):

    print "--- %s ----------------------------------------------" % \
    cls.__name__

    print "type of class %s is '%s'" % ( cls.__name__, type( cls ) )

    before_change = cls('instance created before change')

    print "type of object before_change is '%s'" % type(before_cha nge)

    # 'A' shows that we start with an existing method....
    before_change.E xistingMethod( 'A' )

    print "*** Replacing bound method 'ExistingMethod '..."

    AddBoundMethod( cls, "ExistingMethod ", NewExistingMeth od )

    after_change = cls( 'instance created AFTER change' )

    print "type of after_change is '%s'" % type( after_change )

    # 'B' and 'C' show we've replaced an existing method, both on
    # pre-existing instances and instances created after using
    # AddBoundMethod( )
    before_change.E xistingMethod( 'B' )
    after_change.Ex istingMethod( 'C' )

    print "*** Adding new bound method 'AddedMethod'.. ."

    AddBoundMethod( after_change.__ class__, "AddedMetho d",
    NeverInOriginal Class )

    # 'D' and 'E' show we've added a brand new method, both on
    # pre-existing instances and instances created after using
    # AddBoundMethod( )
    print "%s" % before_change.A ddedMethod( 'D' )
    print "%s" % after_change.Ad dedMethod( 'E' )


    if __name__ == '__main__':

    Test( OldStyleClass )
    Test( NewStyleClass )

    Comment

    • Devan L

      #3
      Re: Adding bound methods dynamically... CORRECTED

      Kevin Little wrote:[color=blue]
      > I want to dynamically add or replace bound methods in a class. I want
      > the modifications to be immediately effective across all instances,
      > whether created before or after the class was modified. I need this
      > to work for both old ('classic') and new style classes, at both 2.3
      > and 2.4. I of course want to avoid side effects, and to make the
      > solution as light-weight as possible.
      >
      > Question for the experts: Is the solution coded in AddBoundMethod( )
      > acceptable to the Pythonian Gods? :) It does seem to work -- tested
      > at 2.3.5 (RH Linux) and 2.4.1 (WinXP)
      >
      > [Code][/color]

      I'm not an expert, but why do you need to dynamically add or replace
      bound methods?

      Comment

      • Gregory Bond

        #4
        Re: Adding bound methods dynamically...

        Kevin Little wrote:
        [color=blue]
        > I want to dynamically add or replace bound methods in a class. I want[/color]


        I asked a seemingly-unrelated question a week or so ago, and learned
        something interesting:

        Python 2.3.4 (#2, Jul 12 2004, 12:46:36)
        [GCC 3.3] on sunos5
        Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
        >>> def foo(self):[/color][/color][/color]
        ... print "foo called"
        ...[color=blue][color=green][color=darkred]
        >>> class C(object):[/color][/color][/color]
        ... pass
        ...[color=blue][color=green][color=darkred]
        >>> type(foo)[/color][/color][/color]
        <type 'function'>[color=blue][color=green][color=darkred]
        >>> C.foo = foo
        >>> type(C.foo)[/color][/color][/color]
        <type 'instancemethod '>[color=blue][color=green][color=darkred]
        >>> c = C()
        >>> c.foo()[/color][/color][/color]
        foo called[color=blue][color=green][color=darkred]
        >>> type(c.foo)[/color][/color][/color]
        <type 'instancemethod '>[color=blue][color=green][color=darkred]
        >>>[/color][/color][/color]

        I.e. assigning a normal function object to a class object turns it into
        a member function!

        You can read more in the thread with the subject 'keeping a ref to a
        non-member function in a class'.

        Comment

        • bruno modulix

          #5
          Re: Adding bound methods dynamically... CORRECTED

          Devan L wrote:[color=blue]
          > Kevin Little wrote:
          >[color=green]
          >>I want to dynamically add or replace bound methods in a class.[/color][/color]

          (snip)
          [color=blue]
          > I'm not an expert, but why do you need to dynamically add or replace
          > bound methods?[/color]

          To modify the behaviour at runtime ?-)

          There are a lot of idioms/patterns in dynamic languages that seems
          somewhat alien at first, then become an obvious solution. When I
          discovered first-class functions and anonymous functions with Python
          some years ago, I wondered what could be the use of such things. Now I
          couldn't live without...

          --
          bruno desthuilliers
          python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
          p in 'onurb@xiludom. gro'.split('@')])"

          Comment

          • Mike Meyer

            #6
            Re: Adding bound methods dynamically... CORRECTED

            bruno modulix <onurb@xiludom. gro> writes:
            [color=blue]
            > Devan L wrote:[color=green]
            >> Kevin Little wrote:
            >>[color=darkred]
            >>>I want to dynamically add or replace bound methods in a class.[/color][/color]
            >
            > (snip)
            >[color=green]
            >> I'm not an expert, but why do you need to dynamically add or replace
            >> bound methods?[/color]
            >
            > To modify the behaviour at runtime ?-)
            >
            > There are a lot of idioms/patterns in dynamic languages that seems
            > somewhat alien at first, then become an obvious solution. When I
            > discovered first-class functions and anonymous functions with Python
            > some years ago, I wondered what could be the use of such things. Now I
            > couldn't live without...[/color]

            Yes, but rather than going through the contortions you do to bind a
            new method into place, why not make the method in question act as a
            proxy for the real method? After all, with first-class functions,
            that's easy.

            <mike
            --
            Mike Meyer <mwm@mired.or g> http://www.mired.org/home/mwm/
            Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.

            Comment

            • Diez B. Roggisch

              #7
              Re: Adding bound methods dynamically... CORRECTED

              >[color=blue]
              > Yes, but rather than going through the contortions you do to bind a
              > new method into place, why not make the method in question act as a
              > proxy for the real method? After all, with first-class functions,
              > that's easy.[/color]

              Because you don't have to write that proxy. Pure lazyness :)


              Diez

              Comment

              • bruno modulix

                #8
                Re: Adding bound methods dynamically... CORRECTED

                Mike Meyer wrote:[color=blue]
                > bruno modulix <onurb@xiludom. gro> writes:
                >[color=green]
                >>Devan L wrote:
                >>[color=darkred]
                >>>Kevin Little wrote:
                >>>
                >>>
                >>>>I want to dynamically add or replace bound methods in a class.[/color]
                >>
                >>(snip)
                >>
                >>[color=darkred]
                >>>I'm not an expert, but why do you need to dynamically add or replace
                >>>bound methods?[/color]
                >>
                >>To modify the behaviour at runtime ?-)
                >>[/color][/color]
                (snip)[color=blue]
                >
                > Yes, but rather than going through the contortions you do to bind a
                > new method into place,[/color]

                Contortion ? Which contortion ?

                class Foo(object):
                def __init__(self, name):
                self.name = name

                def greet1(self, who):
                print "hello %s, this is %s" % (who, self.name)

                def greet2(self, who):
                print "Yo %s, have a drink with Daddy %s" % (who, self.name)

                f = Foo('Python')

                Foo.greet = greet1
                f.greet('Monty' )
                Foo.greet = greet2
                f.greet('Monty' )
                [color=blue]
                > why not make the method in question act as a
                > proxy for the real method?[/color]

                Please show us an implementation.


                --
                bruno desthuilliers
                python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
                p in 'onurb@xiludom. gro'.split('@')])"

                Comment

                • Bruno Desthuilliers

                  #9
                  Re: Adding bound methods dynamically... CORRECTED

                  Kevin Little a écrit :

                  Oops, sorry, forgot to answer
                  [color=blue]
                  > '''
                  > I want to dynamically add or replace bound methods in a class.[/color]
                  (snip)[color=blue]
                  > Is there a more pythonic way that's as straight forward?[/color]

                  What's wrong with:

                  class Foo:
                  pass

                  def method(self):
                  print "%s" % self

                  f = Foo()
                  Foo.method = method
                  f.method()

                  Comment

                  Working...