Adding modified methods from another class without subclassing
John O'Hagan
research at johnohagan.com
Wed Aug 24 13:01:55 CEST 2011
On Mon, 22 Aug 2011 20:38:30 +0200
Peter Otten <__peter__ at web.de> wrote:
> John O'Hagan wrote:
>
> > On Mon, 22 Aug 2011 11:32:18 +0200
> > Peter Otten <__peter__ at 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*
>
> emphasis mine ;)
>
> > , 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. :)
> > [...]
>
> Dunno. Maybe you could inherit from collections.(Mutable)Sequence and
> somewhat reduce the number of methods you'd have to implement.
> Or you introduce a Pitch (Python) class that knows about its pitch class,
> and put that into a normal list:
>
> >>> class Pitch(int):
> ... @property
> ... def pitch_class(self):
> ... return self % 12
> ... def __repr__(self):
> ... return "Pitch(%s, pitch_class=%s)" % (self,
> self.pitch_class)
> ...
> >>> map(Pitch, [1,0,42])
> [Pitch(1, pitch_class=1), Pitch(0, pitch_class=0), Pitch(42, pitch_class=6)]
>
That's a good starting point for a neater solution, but there's more I have to solve. For completeness, here's the un-simplified __init__ of the class (yes, it gets worse!):
class MySeq():
def __init__(self, *sequence, octave=12):
pcset = sorted(set([i % octave for i in sequence]))
steps = ([pcset[i] - pcset[i - 1] for i in range(1, len(pcset))]
+ [octave - pcset[-1]])
rotations = [steps[n:] + steps[:n] for n in range(len(steps))]
prime_steps = min([i for i in rotations if i[-1] == max(steps)])
self.__prime = [0]
for step in prime_steps:
self.__prime.append(step + prime[-1])
self.__offset = pcset[rotations.index(prime_steps)]
self.__order = Order([[prime.index((i - offset) % octave),
(i - self.__offset) // octave] for i in sequence])
self.__octave = octave
The __prime attribute is the one all the internal methods refer to, and it's not so much a collection of pitch classes as an interval structure. Accordingly, I'll follow your tip and look into the collections ABCs, many of which look applicable, and go back to the drawing board.
Thanks,
John
More information about the Python-list
mailing list