Adding method to class at run-time: bad style?
Grant Edwards
grante at visi.com
Tue Apr 7 19:45:15 EDT 2009
On 2009-04-07, Scott David Daniels <Scott.Daniels at Acm.Org> wrote:
> Grant Edwards wrote:
>> On 2009-04-07, Scott David Daniels <Scott.Daniels at Acm.Org> wrote:
>>
>>>> File "/usr/lib/python2.5/site-packages/ClientForm.py", line 2016, in add_to_form
>>>> Control.add_to_form(self, form)
>>>> TypeError: unbound method add_to_form() must be called with FancyControl instance as first argument (got CheckboxControl instance instead)
>>> OK, that is one of the problems with monkey-patching. What happened
>>> is ClientForm apparently defines subclasses of Control such as
>>> CheckboxControl.
>>
>> Right. Control is just a base class, and changing it to a
>> "different" class after sub-classes have been defined pulls the
>> rug out from under things. Had I thought about it for a
>> minute, I should have known that would happen. The working
>> patch tweaks the class in-place, so it works OK.
>>
>>> The monkey-patching only happens after the ClientForm module
>>> has been executed (first import), and the monkey-patching
>>> happens after all of that. So now the "tack it into the
>>> class" method looks a bit better if you cannot simply add your
>>> requirement to the ClientForm source.
>>
>> That's obviously the "right thing", but it makes portability
>> more of an issue (I would have to archive/distribute ClientForm
>> source and users would have to install the customized version
>> of ClientForm).
>>
>> Of course there's always the chance that my version of
>> monkey-patching will stop working with a different version of
>> ClientForm. We'll burn that bridge when we come to it.
>>
>
> What you might use as a half-way measure:
>
> class Mixin: # or class Mixin(object) if new-style:
> def __eq__(self, other):
> return (self.type == other.type
> and self.name == other.name
> and self.value == other.value
> and self.disabled == other.disabled
> and self.readonly == self.readonly)
>
> def __ne__(self, other):
> return not self.__eq__(other)
> ...(including FancyHTMLForm) ...
> class FancyControl(MixIn, ClientForm.Control): pass
> class FancyCheckboxControl(MixIn, ClientForm.CheckboxControl): pass
> ...
> ClientForm.HTMLForm = FancyHTMLForm
> ClientForm.Control = FancyControl
> ClientForm.CheckboxControl = FancyCheckboxControl
That would work -- but there are probably 8 or 10 different
Control subclasses. It's a bit tedious mixing them all one at a
time, and you need more "inside" information (the names of all
the different subclasses).
--
Grant
More information about the Python-list
mailing list