Thursday, December 20, 2012

Python Metaprogramming: Dynamically Adding Methods to Classes

Dynamic addition of methods and attributes to classes and instances.

Dynamic Class Method Addition

Occasionally you may need dynamically add a function as a method to a class.  This is easily accomplished by assigning the function as an attribute of the class.


def fn(self):
  return id(self), self, type(self)

# Traditional Class Definition
class A_Class(object):
  def method_a(self):
    return id(self), self, type(self)

instance = A_Class()

# Modify the class and add fn as a method
setattr(A_Class, 'method_b', fn)

# Call the traditionally defined method
instance.method_a()
# Call the dynamically added method
instance.method_b()



Dynamic Instance Method Addition

When you add the method to a class all instances can access it.  If you only want a particular instance to have a method do this:

from types import MethodType

instance2 = A_Class()
setattr(instance, fn.__name__, MethodType(fn, instance, type(instance)))

# Calls the fn method attached to the instance
instance.fn()

# Throws an exception
instance2.fn()

§

4 comments:

  1. Shouldn't that just be

    instance.fn = MethodType(fn, instance) ?

    ReplyDelete
    Replies
    1. Setattr and assignment are equivalent. However setattr is more flexible in that you can use a variable to hold the name of the attribute you want to set. It allows you to do more meta programming as a result.

      Delete
  2. There is not need in a MethodType, bounded methods are function descriptors.

    class Foo(object):
    pass

    foo = Foo()
    foo.boo = (lambda self: self.bar + 10).__get__(foo)

    foo.bar = 10
    print foo.boo()

    ReplyDelete