Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #12030 > unrolled thread

Re: Adding modified methods from another class without subclassing

Started byJohn O'Hagan <research@johnohagan.com>
First post2011-08-23 00:20 +1000
Last post2011-08-23 00:20 +1000
Articles 1 — 1 participant

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Adding modified methods from another class without subclassing John O'Hagan <research@johnohagan.com> - 2011-08-23 00:20 +1000

#12030 — Re: Adding modified methods from another class without subclassing

FromJohn O'Hagan <research@johnohagan.com>
Date2011-08-23 00:20 +1000
SubjectRe: Adding modified methods from another class without subclassing
Message-ID<mailman.318.1314022820.27778.python-list@python.org>
On Mon, 22 Aug 2011 11:32:18 +0200
Peter Otten <__peter__@web.de> wrote:

> John O'Hagan wrote:
> 
> > I have a class like this:
> > 
> > class MySeq():
> >     def __init__(self, *seq, c=12):
> >         self.__c = c
> >         self.__pc = sorted(set([i % __c for i in seq]))
> >         self.order = ([[self.__pc.index(i % __c), i // __c] for i in seq])
> >         #other calculated attributes
> > 
> >     @property
> >     def pitches(self):
> >         return [self.__pc[i[0]] + i[1] * self.__c for i in self.order]
> > 
> >     #other methods
> 
> That makes me dizzy. Are there any maxims in the Zen of Python that this 
> piece doesn't violate?

"Now is better than never"?

I know it looks crazy to take something apart and put it back together, as in this simplified example, but it does have a meaningful use: reducing a series of musical notes to a unique irreducible form "__pc", ("prime form" in pitch-class set theory), but keeping track of the actual current manifestation of that form via the writeable "order" attribute. That's why "pitches" must be called with each reference, because it may change, unlike "__pc", which can only change if the instance is reinitialised.

I am open to more elegant suggestions, of course. :)
[...]

> > 
> > So I wrote this function which takes a method, modifies it to apply to an
> > instance attribute, and takes care of any quirks:
> > 
> > def listmeth_to_attribute(meth, attr):
> >     def new_meth(inst, *args):
> >         #ensure comparison operators work:
> >         args = [getattr(i, attr)  if isinstance(i, inst.__class__)
> >             else i for i in args]
> >         reference = getattr(inst, attr)
> >         test = reference[:]
> >         result = meth(test, *args)
> >         #ensure instance is reinitialised
> >         #if attribute has been changed:
> >         if test != reference:
> >             inst.__init__(*test)
> >         #ensure slices are of same class
> >         if isinstance(result, meth.__objclass__):
> >             result = inst.__class__(*result)
> >         return result
> >     return new_meth
> > 
> > and this decorator to apply this function to all the list methods and add
> > them to MySeq:
> > 
> > def add_mod_methods(source_cls, modfunc, modfunc_args, *overrides):
> >     """Overides = any methods in target to override from source"""
> >     def decorator(target_cls):
> >         for name, meth in vars(source_cls).items():
> >             if name not in dir(target_cls) or name in overrides:
> >                 setattr(target_cls, name, modfunc(meth, *modfunc_args))
> >         return target_cls
> >     return decorator
> > 
> > a kind of DIY single inheritance, used like this:
> > 
> > @add_mod_methods(list, listmeth_to_attribute, ('pitches',), '__repr__')
> > class MySeq():
> > .....

[...]

>
> In the standard library functools.total_ordering uses that technique and I 
> find the implications hard to understand:
> 
> http://bugs.python.org/issue10042
> 
> Your decorator looks even more complex; I'd only recommend using it if 
> you're absolutely sure you're clever enough to debug it ;)


It looks to me like that total_ordering bug is a result of using comparison operators on objects which may not implement them; I'm pretty sure the listmeth_to_attribute function above can only allow comparing lists with lists or raising an exception. Although I must admit that this creates an unexpected bug/feature whereby lists and MySeqs can be successfully compared, so I take your point! 

Thanks for your reply,

John

[toc] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web