Abstract class

Aaron "Castironpi" Brady castironpi at gmail.com
Sun Sep 14 21:21:54 CEST 2008


On Sep 14, 2:15 pm, Gary Herron <gher... at islandtraining.com> wrote:
> Mr.SpOOn wrote:
> > Gary Harron:
>
> >> I believe you are mixing up class *inheritance* and *abstract* classes.
>
> >> Class inheritance (with Python has has for years) is how one class inherits >behavior/properties/attributes from another class.  The class being inherited from is >called the base class.  This is probably what you want.
>
> > Well, I know the difference between an abstract class and an inherited
> > one. The idea was to create a main class Note, with abstract methods,
> > and implement these methods in the other classes.
>
> > On Sun, Sep 14, 2008 at 7:56 PM, Roy Smith <r... at panix.com> wrote:
>
> >> What properties or behaviors does SharpNote have which NaturalNote doesn't?
> >> Unless there is some new behavior, you don't need subclasses.
>
> > Well, from a SharpNote I can obtain the relative NaturalNote. So if I
> > have a C# I can call
>
> > natural('C#')  and get 'C'
>
> > While in the class NaturalNote I don't need such a method, but I need
> > two methods to get the sharped and flatted version
>
> >> Are you also going to have DoubleSharpNote and DoubleFlatNote?
>
> > Yes, that's an option.
>
> >> Consider the following code:
>
> >> note1 = SharpNote("E4")
> >> note2 = NaturalNote("F4")
> >> if note1 == note2:
> >>   print "the same note"
> >> else
> >>   print "different notes"
>
> >> what should it print?
>
> > Well, that's not so simple. The idea is that I use a notation (A, B,
> > C, D...) and an integer (a distance expressed in semitones) to
> > identify a note.
>
> > Anyway, I think I need an abstract class. Or not?
>
> No!  Definitely not!    You need inheritance of a class from a base
> class.  

Just brainstorming with you.  You can support operations on the
objects: note minus note = interval, note plus interval = note, and so
on.  (WARNING! Spoilers.  Untested.)

note1 = NaturalNote("G")
note2 = NaturalNote("C")
interval= note1- note2
print interval
: <MajorInterval '5th'>

note1 = SharpNote("G")
note2 = NaturalNote("C")
interval= note1- note2
print interval
: <MinorInterval '6th'>

WholeStep= MajorInterval( 2 )
print WholeStep
: <MajorInterval '2nd'>
note1 = NaturalNote("C")
print note1- WholeStep
: <FlatNote("B")>

However, from what I understand (brass player), there are some cases
in which you'll want that to be:

print note1- WholeStep
: <SharpNote("A")>

What do you want to determine that?  What about a KeyOf class?

key= KeyOf( NaturalNote( "F" ) )
#'key' has special subclasses
note1 = key.NaturalNote("C")
print note1- WholeStep
: <FlatNote("B")>

key= KeyOf( SharpNote( "G" ) )
note1 = key.NaturalNote("C")
print note1- WholeStep
: <SharpNote("A")>

Further, perhaps you want a 'WrittenNote' class which refers to the
key signature it's written in:

key= KeyOf( NaturalNote( "F" ) )
note1 = key.WrittenNote("B")
print note1
: <FlatNote("B")>

I do not immediately see how to represent clefs and staves: whether
you'll need them at all, or whether they're just writing/rendering
techniques.

As for scales and chords, are there any special methods you want on
them, or would a tuple of Note instances suffice?

triad= ( NaturalNote( "C" ), NaturalNote( "E" ), NaturalNote( "G" ) )

One special method might be:

triad= Triad( NaturalNote( "C" ), NaturalNote( "E" ),
NaturalNote( "G" ) )
print triad
: <C-Major triad>
triad= Triad( NaturalNote( "E" ), NaturalNote( "G" ),
NaturalNote( "C" ) )
print triad
: <C-Major triad 1st inversion>

I forgot about octaves, which can complicate the constructors.

octave= Octave( 4 ) #middle C
triad= Triad( octave.NaturalNote( "E" ), octave.NaturalNote( "G" ),
octave.up.NaturalNote( "C" ) )
print triad
: <C-Major triad 1st inversion>

Or:

octave= Octave( 4 )
triad= Triad( NaturalNote( "E", octave ), NaturalNote( "G", octave ),
NaturalNote( "C", octave.up ) )
print triad
: <C-Major triad 1st inversion>

And abbreviate the name for the interval.

octaveint= MajorInterval( 8 )

Abstract scales can be a tuple of intervals, where concrete scales are
a tuple of notes.

majorscale= ( Tonic, WholeStep, WholeStep, HalfStep,
    WholeStep, WholeStep, WholeStep, HalfStep )

majorCscale= [ NaturalNote( "C" )+ x for x in majorscale ]
majorDscale= [ NaturalNote( "D" )+ x for x in majorscale ]

To get a little more creative, you could just denote sharps and flats
with a parameter:

note1 = Note("G", sharp)
#Or: note1 = Note("G", Note.sharp)
note2 = Note("C")
interval= note1- note2
print interval
: <MinorInterval '6th'>

It would just take some 'parameter magic' to interpret them right when
paired with octaves:

octave= Octave( 4 ) #middle C
note1= Note( "C", sharp, octave )
note2= Note( "C", octave )
note3= Note( "C", octave, sharp )
note4= Note( "C", sharp )

That part just takes a little untwisting.  (Untested.)

class Note:
   defaultoctave= 4
   def __init__( self, *args ):
       octave= Octave( self.defaultoctave )
       accidental= Natural( )
       for arg in args:
          if issubclass( arg, Accidental ):
             accidental= arg
          elif issubclass( arg, Octave ):
             octave= arg
          elif type( arg ) is str:
             name= arg

Or use keywords to specify.

octave= Octave( 4 ) #middle C
note1= Note( "C", sharp, octave )
note2= Note( "C", octave= octave )
note3= Note( "C", octave= octave, accidental= sharp )
note4= Note( "C", sharp )

class Note:
   defaultoctave= 4
   def __init__( self, name, octave= None, accidental= Natural( ) ):
       if octave is None:
           octave= self.defaultoctave

It's open to debate whether Natural is a subclass or instance of
Accidental.



More information about the Python-list mailing list