Feedback on Pitch Constellation/ Chromatic Circle in Python Project Hello I'm doing a mini project that is modeled after pitch constellation.
--&gt; https://en.wikipedia.org/wiki/Chromatic_circle
Basically, pitch constellation is modeled after a clock where each note is assigned a number. When the wheel goes clockwise it goes up the scale, and when it goes counterclockwise it goes down. I thought this might be a great idea for a midi project. (My project only goes up the scale.)
Here's how it works:

It prompts for an input of a music note and then shifts the elements so that the list will start with the root key. Then it will return the notes starting with the root note or the note selected.

Then it prompts to enter what mode to return the music note values. The way this done is by assigning the elements in the returned notes to the value selected in the dict variable scale. Which will then select the index number of the items and create a new list.

Lastly, it returns the scale with the key and mode.


That's all it does so far. Eventually, I'd like to combine it with a midi module I found in pythons open library and then have it send midi out. I want to get honest feedback on what areas can be improved in my program before I go any further.


notes = ['C', 'C#', 'D', 'D#',
             'E', 'F', 'F#', 'G', 'G#',
             'A', 'A#','B']

scale = {'major':[0, 2, 4, 5, 7, 9, 11],
    'minor':[0, 2, 3, 5, 7, 8, 10],
    'phrygian':[0, 1, 3, 5, 7, 8, 10],
    'lydian':[0, 2, 4, 6, 7, 9, 11],
    'mixolydian':[0, 2, 4, 5, 7, 9, 10],
    'aeolian':[0, 2, 3, 5, 7, 8, 10],
    'locrian':[0, 1, 3, 5, 6, 8, 10],
    'chromatic':[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
    'wholetone':[0, 2, 4, 6, 8, 10],
    'diminished7thchord': [0, 3, 6, 9],
    'augmentedchord':[0, 4, 8],
    'tritone':[0, 6]}


rootkey = input(&quot;Enter the root Note: &quot;).upper()

class CircleFifths:
    &quot;&quot;&quot;docstring for CircleFifths.&quot;&quot;&quot;
    def __init__(self, key):
        self.rootkey = rootkey

    def shift(self, rootkey, index=0, s=0,):
        #shifts the leading item (rootkey) entered by the user down the list
        #removes the last term and puts it as the first term
        while index &lt; 12 and s &lt;12:
            s += 1
            index += 1
            new_notes = notes[-s:] + notes[:-s]
            if rootkey == new_notes[0]:
                print(new_notes)
                return new_notes



def main():
    a = CircleFifths(rootkey)
    key = a.shift(rootkey)

    keymode = []

    print('Select a scale and enter it below')
    for k in scale:
        print(k)

    mode = input(&quot;Enter the mode: &quot;).lower()
    try:
        x = scale.get(mode)
        keymode = [key[i] for i in x]
        print(keymode)
    except:
        if mode not in scale:
            print(&quot;Scale not in list. Please start the program again.&quot;)
        return

main()
Immutable sequences
Convert notes and the values in scale from list literals [] to tuple literals () since it's expected that they cannot and will not change.
Musical theory
Consider distinguishing between harmonic and melodic minor, which are different scales.
Global code
Move
rootkey = input(&quot;Enter the root Note: &quot;).upper()

into your main(). Also, your constructor
def __init__(self, key):
    self.rootkey = rootkey

needs to refer to its key argument and not the rootkey global.
Shadowing
def shift(self, rootkey, index=0, s=0,):

has a number of issues:

You're shadowing the global rootkey with an identically-named argument
You shouldn't have a rootkey argument at all, since it's already a member on self

Loop like a native
Consider renaming index and s to first_index and first_s, so that you can replace your while with
for index, s in zip(
    range(first_index, 12),
    range(first_s, 12)
):

Inner prints
Delete the print from here:
            print(new_notes)
            return new_notes

If you want to print it, do so at the outer level.
Logic by exception
Consider writing
mode = input(&quot;Enter the mode: &quot;).lower()
try:
    x = scale.get(mode)
    keymode = [key[i] for i in x]
    print(keymode)
except:
    if mode not in scale:
        print(&quot;Scale not in list. Please start the program again.&quot;)
    return

as
mode_name = input(&quot;Enter the mode: &quot;).lower()
mode = scale.get(mode_name)
if mode is None:
    print(f&quot;Scale {mode_name} not in list. Please start the program again.&quot;)
else:
    key_mode = [key[i] for i in mode]
    print(key_mode)

In other words, where possible do not rely on exceptions (especially with no type specified) to govern your logic; and avoid a double-dictionary lookup by using get.