как мне исправить эти ошибки? Генератор табуляций для бас-гитары

#python

#python

Вопрос:

Я работаю над каким-то программным обеспечением, которое будет генерировать табы для бас-гитары (используя только 4 струны и лады 0-12 я пытался определить эти глобальные значения везде, но это не работает. Также в чем ошибка при вызове функции?

Ошибки:

Обратная трассировка (последний вызов last): Файл "/home/olaf/Documents/Projects/BassComposer/main.py" , строка 69, в generator(fret, string) файле «/home/olaf/Documents/Projects/BassComposer/main.py «, строка 62, в generator tab3 = str(fret) NameError: name 'tab3' не определено

 from random import randint

try:
    times =str(int(input("How many notes do you want to be created?nn")))
except:
    print("nInvalid input!n")

print("nnGenerating "   times   " note(s) long basslinen...nn")

startString = randint(0, 3)
startFret = randint(0, 9)

string = startString
fret = startFret

notes = int(times)




def generator(fret, string):
    global tab0
    global tab1
    global tab2
    global tab3
    x = randint(0,11)
    y = randint(0,16)
    if x in range(4, 9):
        if x in range(4, 7) and fret in range(0,11):
            fret  = 1
            if x in range(4, 5) and fret in range(0, 11):
                fret  = 1
    if x in range(8,11) and fret in range(1,12):
        fret -= 1
        if x in range(10,11) and fret in range(1, 12):
            fret -= 1
    if y in range(11,16):
        if y in range(11, 13) and string in range(0,2):
            string  = 1
            if (y == 13) and string in range(0,2):
                string  = 1
        if y in range(14, 16) and string in range(1, 3):
            fret -= 1
            if (y==16) and string in range(1, 3):
                fret -= 1
    if string == 0:
        tab0  = str(fret)
        tab1  = " "
        tab2  = " "
        tab3  = " "
    if string == 1:
        tab1  = str(fret)
        tab0  = " "
        tab2  = " "
        tab3  = " "
    if string == 2:
        tab2  = str(fret)
        tab0  = " "
        tab1  = " "
        tab3  = " "
    if string == 3:
        tab3  = str(fret)
        tab0  = " "
        tab1  = " "
        tab2  = " "


for notes in range(0, notes):
    generator(fret, string)
    notes -= 1
  

Я был бы благодарен, если бы кто-нибудь сказал мне, чем вызваны эти проблемы и как их исправить

Комментарии:

1. global не создает переменные. Все, что он делает, это изменяет область переменной, потому что присвоение имени в функции делает переменную локальной без global указания на обратное. Вы не указали tab1 и т.д. любое значение в любом месте, так что вы также не можете добавить к ним больше.

2. Вы должны сначала установить переменную, прежде чем сможете ее прочитать. Добавление некоторой строки также должно быть сначала прочитано.

Ответ №1:

global это оператор, который объявляет область видимости переменной, а не создает ее. Если вы хотите, чтобы ваш код просто работал, вы должны написать это перед generator функцией:

 tab0 = ""
tab1 = ""
tab2 = ""
tab3 = ""
  

…НО!

Это очень плохая практика. Кроме того, в вашем коде есть еще несколько серьезных проблем, которые не вызывают ошибок, но делают ваш код очень неясным и сложным в обслуживании. Итак, давайте исправим их и сделаем ваш код красивым 🙂

  1. Глобальные переменные и глобальный оператор — очень плохая практика. Вы никогда не можете быть уверены, что какая-то глобальная переменная будет правильной и будет иметь значение, которое вы ожидаете увидеть. В 99,9% случаев использование глобальных переменных не является вариантом и может быть заменено локальными переменными. Если вам действительно нужна глобальная инструкция, вы можете использовать какие-нибудь файлы конфигурации. Ваша generator функция изменяет состояние четырех глобальных переменных и не сохраняет результат, и мы можем переписать его с помощью:
 def generator(fret, string):
    tab0 = ""
    tab1 = ""
    tab2 = ""
    tab3 = ""
    for notes in range(0, notes):
        # All your another code
    return tab0, tab1, tab2, tab3
...
tab0, tab1, tab2, tab3 = generator(...)
  
  1. У вас есть четыре логически равные переменные: tab0, tab1, tab2, tab3 . Что, если кто-нибудь захочет запустить этот код для бас-гитары с 6 табуляциями? На самом деле наши табуляции являются частью одной сущности — табуляции … err … таблицы (я не музыкант, извините). Таким образом, мы можем объединить их в один объект — список вкладок!

tab_list = []

С его помощью наш код:

 tab0  = str(fret)
tab1  = " "
tab2  = " "
tab3  = " "
  

преобразует в:

tab_list.append((str(fret), None, None, None)) (не беспокойтесь о Nones, мы можем преобразовать их позже)

Теперь у нас есть этот код:

     if string == 0:
        tab_list.append(str(fret), None, None, None)
    if string == 1:
        tab_list.append(None, str(fret), None, None)
    if string == 2:
        tab_list.append(None, None, str(fret), None)
    if string == 3:
        tab_list.append(None, None, None, str(fret))
  

Видите шаблон? 🙂 str(fret) Индекс равен string значению! Таким образом, мы сжимаем его еще больше:

     tabs_to_append = [None, None, None, None]
    tabs_to_append[string] = str(fret)
    tab_list.append(tabs_to_append)
  

И мы сжимаем 20 строк кода в 3!

  1. Эта часть кода:
 for notes in range(0, notes):
    generator(fret, string)
    notes -= 1
  

повторяется для 0 .. нот, но! имя индекса равно границе диапазона и изменяется внутри. Это очень, очень, ОЧЕНЬ плохая практика! В этом случае это сработает (и это странно), но в большинстве случаев это даст много неожиданных результатов, которые заставят вас отлаживать их час за часом. Итак, мы переписываем его как:

 for _ in range(0, notes):  # We don't really need this index
  
  1. Ненужная логика:

Я объясню эту часть в этом фрагменте кода:

 1. if x in range(4, 9):
2.         if x in range(4, 7) and fret in range(0,11):
3.             fret  = 1
4.             if x in range(4, 5) and fret in range(0, 11):
5.                 fret  = 1
  

У вас есть первый оператор if, который проверяет, x равен 4 .. 9. Но внутри есть только один оператор if, который проверяет, x равен 4 .. 7. Это означает, что первый оператор if бесполезен, поэтому мы можем просто удалить его (или внутри есть логическая ошибка). Кроме того, оба if-оператора в строках 2 и 4 имеют fret in range(0, 11) . Мы можем переместить его в первую строку и получить этот код:

 1. if fret in range(0,11):
2.         if x in range(4, 7):
3.             fret  = 1
4.             if x in range(4, 5):
5.                 fret  = 1
  

Теперь посмотрите на if-оператор в строке 4. range(4, 5) возвращает один список элементов [4] . Итак, эта строка преобразуется в: if x == 4: . Теперь мы можем, наконец, изменить наш блок кода:

 1. if fret in range(0,11):
2.       if x in range(5, 7):
3.           fret  = 1
4.       elif x == 4:
5.           fret  = 2
  

Вы можете преобразовать другие свои блоки логического кода. Я уверен, что это будет значительно упрощено (возможно, даже будет объединено с блоком, который мы переписали сейчас).

И, наконец, у нас есть наша новая программа:

 from random import randint

try:
    times = int(input("How many notes do you want to be created?nn"))
except:
    print("nInvalid input!n")

print("nnGenerating "   str(times)   " note(s) long basslinen...nn")

startString = randint(0, 3)
startFret = randint(0, 9)


def generator(startFret, startString, times):
    string = startString
    fret = startFret
    tab_list = []

    for _ in range(times):
        x = randint(0, 11)
        y = randint(0, 16)

        # Transformed
        if fret in range(0,11):
            if x in range(5, 7):
                fret  = 1
            elif x == 4:
                fret  = 2

        # Old, removed unnesessary if-statements
        if x in range(8,11) and fret in range(1,12):
            fret -= 1
            if x in range(10,11):
                fret -= 1
        if y in range(11, 13) and string in range(0,2):
            string  = 1
            if (y == 13):
                string  = 1
        if y in range(14, 16) and string in range(1, 3):
            fret -= 1
            if (y==16):
                fret -= 1

        tabs_to_append = ["_", "_", "_", "_"]
        tabs_to_append[string] = str(fret)
        tab_list.append(tabs_to_append)
    return tab_list

tabs = generator(startFret, startString, times)

# Converts list of time-tabs to strings of tabs-timeline
tabs_str = [
    " ".join([
        tabs[i][j]
         for i in range(len(tabs))
    ])
    for j in range(4)
]
for s in tabs_str:
    print(s)
  

Его можно улучшить еще больше (конечно, почти каждая программа может :)), но я очень устал, извините. Я думаю, что я немного помог вам с моим длинным-длинным цифровым папирусом.

P.S. Ваш генератор возвращает табуляции только для одной вкладки. Я думаю, у вас логическая ошибка в коде вашего генератора. Я не знаю, что вы хотите сгенерировать, поэтому я не буду давать вам никаких советов.