Adding method to class at run-time: bad style?

Grant Edwards invalid at invalid
Tue Apr 7 14:38:11 EDT 2009


On 2009-04-07, Scott David Daniels <Scott.Daniels at Acm.Org> wrote:
> Grant Edwards wrote:
>> I realize that technically all methods are added to classes at
>> "run-time", but what I'm talking about is this:
>> 
>>    import ClientForm
>> 
>>    def controlEqual(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)
> Note:
> Here you are checking that self.readonly == self.readonly!

Doh!

> I also dislike the trailing backslashes and over-parenthesizing.
> So, I'd do it like this (using the pare to avoid the backslash):

The paren to avoid the backslashes is a good tip.

>       def controlEqual(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)

I don't really like to rely on my memory of operator
precidence, but that's a personal problem.

> ...
>>    ClientForm.Control.__eq__ = controlEqual
>>    ClientForm.Control.__ne__ = controlNotEqual
>>    
>>    def formEqual(self,other):
>>        if len(self.controls) != len(other.controls):
>>            return False
>>        for (c1,c2) in zip(self.controls,other.controls):
>>            if c1 != c2:
>>                return False
>>        return True
>>    
>>    def formNotEqual(self,other):
>>        return not (self==other)
>>    
>>    ClientForm.HTMLForm.__eq__ = formEqual
>>    ClientForm.HTMLForm.__ne__ = formNotEqual
>
>> It works fine, but it seems like it might be dangerous (or just
>> bad form) to insert methods into existing classes like that.
>> Perhaps it would be safer to make sure that __eq__, __ne__,
>> and __cmp__ don't exist before adding my own?
>
> Well, a more standard approach would be:
>      class FancyControl(ClientForm.Control):
>          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)
>
>      class FancyHTMLForm(ClientForm.HTMLForm):
>          def __eq__(self,other):
>              ...
>
>          def __ne__(self, other):
>              return not self.__eq__(other)
>
> You'd have to make sure FancyControl and FancyClientForm get used in
> the app.

The problem is that my app never instanciates either the
Control or the HTMLForm class: that's all done by module
functions that the app calls, and they don't know about the new
classes without some trickery (e.g. below)

> The latter could be insured by monkey-patching:
>      ...
>      ClientForm.Control = FancyControl
>      ClientForm.HTMLForm = FancyHTMLForm
>
> But substituting monkey-patching

:) How did I not know that phrase until today?

> for class method insertion seems like you are going from one
> quick and dirty technique to a slightly nicer quick and dirty
> technique.

I think like your monkey-patching solution better.  It feels a
bit cleaner.

-- 
Grant Edwards                   grante             Yow! !  Up ahead!  It's a
                                  at               DONUT HUT!!
                               visi.com            



More information about the Python-list mailing list