From: Vladimir.Marangozov at inrialpes.fr (Vladimir Marangozov)
Date: Thu, 08 Apr 1999 05:56:52 +0200
Subject: Chaning instance methods
References: <tx3soadh4jj.fsf@hog.ldgo.columbia.edu>
Message-ID: <370C2904.A6F4BD54@inrialpes.fr>
Content-Length: 2832
X-UID: 319                                                  

Jody Winston wrote:
> 
> I don't understand how to change instance methods. For example:
> ...
> What am I forgetting?

On a first thought, you seem to forget Python's internals (that you're
supposed to forget, BTW) and people helped you generously on this by
introducing you, and me, to trickery.

On a second thought, I'll follow their example ;-) but I'll try to do it
the easy (OO) way; it's easy enough not to be described so far, but it
seems more logical to me, so here goes.

If Foo is a class and f is an instance of Foo, by changing the instance
method f.m (for whatever insane reason), one augments f's behavior beyond
the limits prescribed by Foo. By doing so, one withdraws f from the set of
"similar" objects, instances of Foo, that share a common set of properties
(operations), defined by the Foo class. (right, this is Object theory).

Indeed, f becomes some particular object which is no more part of the Foo
gang. Pushing that further, we have reasons to believe that after the
change, we're in a situation where f belongs to some Bar gang, where
Foo and Bar differ only in the 'm' method, just like if f were an instance
of Bar from the start.

In fact, it is Bar that has the desired augmented interface, not f.
Bar is the incarnation of the desired incremental code evolution <ahem>
done the OO way through class inheritance (not with instance hacking).

Thus we arrive at the easy & boring solution, which goes along these lines:
(it's an instance hack too, but a recognized one in metaobject communities)

>>> class Foo:
...     def m(self):
...         print "Foo.m"
...
>>> f = Foo()
>>> f.m()
Foo.m
>>>
>>> def m2(self):
...     print "m2"
...
>>> class Bar(f.__class__): pass
...
>>> Bar.m = m2
>>>
>>> f.__class__ = Bar # f changes its camp
>>> f.m()
m2

Since we do ignore Python's internals, we do not notice that the
price to pay by f for deserting the Foo gang & joining Bar's is
an additional level of indirection for all accesses to Foo's methods.

The good news are that if f is really a rebel instance and it wants
to change camps frequently, one can use the dedicated Bar proxy class
for storing new methods at will, without affecting Foo, nor its instances.
In a sense, this also avoids the tricky solutions resulting from
peculiarities of the class/instance implementation -- a good candidate
for major changes in Python2. We won't escape these changes, unless we
manage to increase bus traffic around CNRI or so ;-)

To make a long story short, what you're trying to do is not very cool,
so perhaps you don't get truly cool answers, but still, you can do it
in Python. Fortunately, what you're asking here is not common practice,
I hope!

-- 
       Vladimir MARANGOZOV          | Vladimir.Marangozov at inrialpes.fr
http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252




