Adding method at runtime - problem with self
Bruno Desthuilliers
bdesth.quelquechose at free.quelquepart.fr
Sun Mar 5 21:56:13 EST 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