Adding method at runtime - problem with self

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Mon Mar 6 03:56:13 CET 2006


marek.rocki at wp.pl a écrit :
> First of all, please don't flame me immediately. 

Granted - we'll do it later then !-)

> I did browse archives
> and didn't see any solution to my problem.
> 
> Assume I want to add a method to an object at runtime. Yes, to an
> object, not a class - because changing a class would have global
> effects and I want to alter a particular object only. The following
> approach fails:
> 
> class kla:
>     x = 1
> 
> def foo(self):
>     print self.x
> 
> k = kla()
> k.foo = foo
> k.foo()
> 
> I know where the problem is. The method shouldn't have 'self'
> parameter.

Yes it should - else :

> But how do I access object's attributes without it?

Hey, how's Python itself doing ?-)

The problem with your code is that foo is a function object, not a 
method object. So you need to turn it into a method object - which is 
(overly simplification ahead) an object that bind a function object to 
an instance and takes care of passing the instance as first param to 
that function (hint: google for 'descriptor').

Hopefully, function objects provide a method that allow to bind them to 
instances :

>>> class Toto(object):
...     def __init__(self, name): self.name = name
...
>>> t1, t2 = Toto('t1'), Toto('t2')
>>> def fun(self): 
...     print self.name
>>> t1.fun = fun.__get__(t1)
>>> t1.fun()
t1

FWIW, you would have the same result (which much less pain) by simply 
passing the instance to the function !-) (there's nothing special about 
the word 'self')

If what you want to do is to provide a specific implementation for a 
given method on a per-instance base, you can do it much more explicitely:

class MyObject(object):
   def __init__(self, name, custom_do_this=None):
     self.name = name
     self._custom_do_this = custom_do_this

   def _do_this_default(self):
      return "default do_this implementation for %s" % self.name

   def do_this(self):
      if callable(self._custom_do_this):
         return self._custom_do_this(self)
      else:
         return self._do_this_default()

def custom_do_this(obj):
   return "custom do_this implementation for %s" % obj.name

myobj = MyObject('myobj')
print myobj.do_this()
myobj._custom_do_this = custom_do_this
print myobj.do_this()

Agreed, this is not exactly the same thing as *adding* a method, but 
it's (IMHO) somewhat cleaner wrt/ encapsulation and LSP. (Note that you 
can make the default implementation a no-op - the point here is that the 
client code shouldn't have to worry about MyObject's instances having or 
not having a custom implementation for do_this).

My 2 cents...



More information about the Python-list mailing list