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