Почему python выдает мне UnboundLocalError при запуске этой программы?

#python #function #compiler-errors #global-variables

#питон #функция #ошибки компилятора #глобальные переменные

Вопрос:

Предыстория

В настоящее время я экспериментирую с компьютерным обучением, и я создал функцию, в которой вы вводите «true» или «false», и компьютер узнает, какое это логическое значение, после чего программа печатает процент правильных догадок, сделанных компьютером:

 import math
import random
endgame = False
def oneround():
    Q1max = 1
    Q1min = -2
    guess = False
    answer = 0
    while guess == False:
        useranswer = input("True or False?")
        if useranswer == "True" or useranswer == "true":
            answer = True
            guess = True
        elif useranswer == "False" or useranswer == "false":
            answer = False
            guess = True
        
    corrects = 0
    incorrects = 0 
    howmanytimes = int(input("how many times do you want the computer to guess? (If you want to end the game, type in letters instead of a number.) "))
    for x in range(0,howmanytimes):
        choice = random.randint(Q1min,Q1max)
        if choice >= 0:
            guess = True
        else:
            guess = False
        if guess == answer:
            corrects  = 1
            if guess == True:
                Q1max  = 1
            else:
                Q1min -= 1
        else:
            incorrects  = 1
            if guess == False:
                Q1max  = 1
            else:
                Q1min -= 1
    percent = (corrects/howmanytimes)*100
    print ("The computer learned to guess correctly",(str(math.floor(percent)) "%"),"of the time.")
while endgame == False:
    try:
        oneround()
    except ValueError:
        endgame = True
 

Затем я попытался улучшить свою программу, добавив 2 глобальные переменные, percentavg и percentavgnum это приведет к усреднению всех процентов успеха в конце программы:

 import math
import random
endgame = False
global percentavg
global percentavgnum
percentavg = 0
percentavgnum = 0
def oneround():
    Q1max = 1
    Q1min = -2
    guess = False
    answer = 0
    while guess == False:
        useranswer = input("True or False?")
        if useranswer == "True" or useranswer == "true":
            answer = True
            guess = True
        elif useranswer == "False" or useranswer == "false":
            answer = False
            guess = True
        
    corrects = 0
    incorrects = 0 
    howmanytimes = int(input("how many times do you want the computer to guess? (If you want to end the game, type in letters instead of a number.) "))
    for x in range(0,howmanytimes):
        choice = random.randint(Q1min,Q1max)
        if choice >= 0:
            guess = True
        else:
            guess = False
        if guess == answer:
            corrects  = 1
            if guess == True:
                Q1max  = 1
            else:
                Q1min -= 1
        else:
            incorrects  = 1
            if guess == False:
                Q1max  = 1
            else:
                Q1min -= 1
    percent = (corrects/howmanytimes)*100
    percentavg  = percent
    percentavgnum  = 1
    print ("The computer learned to guess correctly",(str(math.floor(percent)) "%"),"of the time.")
while endgame == False:
    try:
        oneround()
    except ValueError:
        endgame = True
print ("The computer guessed correctly",(str(math.floor(percentavg/percentavgnum)) "%"),"of the time")
 

Проблема

Но я продолжаю получать эту ошибку при каждом запуске программы:

 Traceback (most recent call last):
  File "main.py", line 49, in <module>
    oneround()
  File "main.py", line 44, in oneround
    percentavg  = percent
UnboundLocalError: local variable 'percentavg' referenced before assignment
 

Кто-нибудь знает, что я делаю не так?

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

1. Вместо использования глобальной переменной попросите вашу функцию вернуть вычисленное значение (значения); присвоите возвращаемое значение (значения) переменным уровня модуля, передайте переменные уровня модуля функции.

2. @wwii Можете ли вы сформулировать это немного проще?

3. Смотрите мой ответ …

Ответ №1:

Используйте global . Поместите его в начало функции с именами переменных после него. Вот так: global percentavg, percentavgnum
ПРИМЕЧАНИЕ: имена должны быть разделены запятыми.

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

1. Это возвращает синтаксическую ошибку для этой строки.

2. Это несколько правильно, но не объясняет почему ! global убедитесь, что имя, на которое ссылается ссылка, находится в глобальной области видимости (в противном случае его нельзя отличить от нового имени в области видимости функции). Поместите по одному на строку

3. @ti7 Ах да, забыл об этом. Все они могут быть в одной строке, если вы разделяете их запятыми.

4. Так почему я получал сообщение об ошибке? Пожалуйста, включите это в свой ответ.

5. @jeffthechicken Готово.

Ответ №2:

Эта проблема связана с тем, как Python определяет область видимости переменной.

Вы можете заметить, что ошибка возникает при попытке увеличить percentavg с помощью percentavg = percent .

Итак, вы пытаетесь присвоить новое значение percentavg .

Дело в том, что в Python, когда вы присваиваете значение переменной, переменная становится локальной переменной. Но percentavg не был определен в этой области (область действия oneround() , и поэтому вы получаете это UnboundLocalError .

Все это подробно объясняется здесь: https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value

У вас есть как минимум 3 варианта:

  1. Определите переменные в oneround() :
 def oneround():
    percentavg = 0
    percentavgnum = 0
    # ...
 
  1. Передайте свои переменные в качестве аргументов oneround() :
 percentavg = 0
percentavgnum = 0
oneround(percentavg,percentavgnum)
 

И вам вообще не нужно объявлять свои переменные как глобальные.

  1. Доступ к вашим внешним переменным области видимости, используемым global внутри вашей функции:

(Это то, что предложил @Blue)

 def oneround():
    global percentavg
    global percentavgnum
 

Ключевая строка global используется для доступа к переменным внешней области видимости (переменным, объявленным вне области действия функции).

Если вы выберете вариант 1, вы можете удалить эти строки в начале вашего кода:

 global percentavg
global percentavgnum
percentavg = 0
percentavgnum = 0
 

Если вы выберете вариант 2, вы можете удалить эти строки в начале вашего кода:

 global percentavg
global percentavgnum
 

но вам придется сохранить эти строки:

 percentavg = 0
percentavgnum = 0
 

Эти строки могут быть в начале вашего кода, но это может быть в цикле while или в инструкции try перед вызовом oneround() .

Но, основываясь на вашем фрагменте кода, вариант 1 является лучшей практикой кодирования.

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

1. Итак, я делаю его глобальным, объявляя его В функции?

2. Нет, вам вообще не нужно делать их глобальными. Я отредактирую свой ответ, чтобы объяснить это.

3. Я в замешательстве, когда мне нужно использовать эту функцию?

Ответ №3:

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

 >>> def f(one,two,three):
...     return one*1,two*2,three*3
...
>>> a,b,c = 'xyz'
>>> a,b,c = f(a,b,c)
>>> a
'x'
>>> b
'yy'
>>> c
'zzz'
>>>