#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, в generatortab3 = 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 = ""
…НО!
Это очень плохая практика. Кроме того, в вашем коде есть еще несколько серьезных проблем, которые не вызывают ошибок, но делают ваш код очень неясным и сложным в обслуживании. Итак, давайте исправим их и сделаем ваш код красивым 🙂
- Глобальные переменные и глобальный оператор — очень плохая практика. Вы никогда не можете быть уверены, что какая-то глобальная переменная будет правильной и будет иметь значение, которое вы ожидаете увидеть. В 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(...)
- У вас есть четыре логически равные переменные:
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!
- Эта часть кода:
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. 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. Ваш генератор возвращает табуляции только для одной вкладки. Я думаю, у вас логическая ошибка в коде вашего генератора. Я не знаю, что вы хотите сгенерировать, поэтому я не буду давать вам никаких советов.