#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 варианта:
- Определите переменные в
oneround()
:
def oneround():
percentavg = 0
percentavgnum = 0
# ...
- Передайте свои переменные в качестве аргументов
oneround()
:
percentavg = 0
percentavgnum = 0
oneround(percentavg,percentavgnum)
И вам вообще не нужно объявлять свои переменные как глобальные.
- Доступ к вашим внешним переменным области видимости, используемым
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'
>>>