85 lines
3.1 KiB
Plaintext
85 lines
3.1 KiB
Plaintext
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
|
|
|
|
|
|
|
|
|