当我 运行 这个程序时,为什么 python 给我一个 UnboundLocalError?

Why is python giving me an UnboundLocalError when I run this program?

背景

我目前正在试验计算机学习,我做了一个函数,你输入“真”或“假”,计算机就会知道它是哪个布尔值,之后程序会打印出计算机做出的正确猜测的百分比:

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 个全局变量 percentavgpercentavgnum 来改进我的程序,这将在程序结束时对所有成功百分比进行平均:

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

有谁知道我做错了什么吗?

使用global。把它放在函数的顶部,后面是变量名。像这样:global percentavg, percentavgnum
注意:名称必须以逗号分隔。

这个问题与Python如何确定变量的范围有关。

您可以注意到当您尝试通过 percentavg += percent.

递增 percentavg 时发生错误

所以您正在尝试分配一个新值给percentavg

问题是在Python中,当你给一个变量赋值时,这个变量就变成了一个local变量。但是 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

这些行可能在代码的开头,但也可能在调用 oneround().

之前的 while 循环或 try 语句中

但是,根据您的代码,选项 1 是最佳编码实践。

与其使用全局变量并依赖函数的副作用,不如编写函数以接受需要 更新 的模块级变量作为参数,并将 return 更新 值。

>>> 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'
>>>