Python Error - UnboundLocalError: local variable xxx referenced before assignment

1 写在前面

UnboundLocalError 产生的原因很简单,就是后面「错误提示语句」的直译 “局部变量使用前未初始化”。但由于我们对 Python 语法的一些细节不熟悉,也由于 Python 语法过于灵活,可能明知这个原因也分析不出自己的代码哪里有问题。所以这里总结一下这个问题可能的原因,以及涉及的 Python 语法知识。

① 局部变量 & 全局变量相关的原因

语法知识:局部变量(主要指函数内的局部变量),与全局变量重名时,Python 解释器什么时候认定其为重名局部变量(语法允许),什么时候认定其为全局变量

  • 重名变量,在函数内有全局声明时,当然为全局变量

  • 除此之外,当重名变量在函数内存在(可以不是在函数内第一次出现时)赋值语句(包括 += 语句)时,它被认定为局部变量,否则被认为是全局变量。

插说一句,这个语法规则很容易理解。因为当出现赋值语句时,说明重名变量在函数内的值已经与函数外的值完全无关,重新赋了个新值,所以完全没有必要视之为全局变量。

这就导致,当 函数内的、与函数外全局变量重名的变量,第一次在函数中出现不是赋值语句,而后面又在函数中出现了它的赋值语句 时,Python 解释器会报 “UnboundLocalError” 错误。这种情况的产生又分两种原因:

  1. 重名变量是全局变量,忘记对其用 global 关键字声明就使用(这种情况,如果后面没有赋值语句也无妨,解释器也会认为它是全局变量),但后面又出现了赋值语句,使 Python 解释器误解析为局部变量
  2. 重名变量是局部变量,忘记初始化了

修改方法不言而喻,是全局变量则用 global 声明,否则在第一次使用前初始化为期望的值。

② 函数中用到了判断语句,而局部变量的初始化语句放在了某条分支下

这会导致,在其他分支情况下,在判断语句外使用此变量时它并未初始化,解释器报错 “UnboundLocalError”。

修改方法就是把该初始化语句放到判断语句前面。


如果到这里可以明确自己所遇到的 “UnboundLocalError” 产生的原因,就不必看下面案例的模拟代码了;如果还不清楚,请继续向下看。

2 模拟代码

场景一 局部变量和全局变量重名

这种情况其实不太容易出现,因为很多IDE会直接用红波浪线警告。比如下面两种情况:

xxx = 1

def run():
    #  += 运算,先使用(+)再赋值(=)
    xxx += 2 # xxx被认为是局部变量,且初始化前就用它加2,报错UnboundLocalError

run()
x = []

def run():
    x.append(2)
    x = [3,4] # 先使用,再赋值,报错UnboundLocalError

run()

修改方法正如开头所讲,要么在函数内用 global 关键字将变量声明为全局变量,要么把变量的赋值语句放在它被调用之前。

场景二 局部变量初始化语句放在判断语句某个分支中

今日执行 Python 代码遇到 ‘UnboundLocalError’ 时的场景就是如此,从中抽取出了下面的核心模拟代码:

def func(flag=True):
    
    # xxx = 3 # 正确的做法
    
    if flag: 
        xxx = 3
        ...
    
    return xxx

# func()    # 未报错
func(False) # 报错 UnboundLocalError

这段代码,使用默认参数时可正常运行;当修改参数为 False 时,会运行报错 “UnboundLocalError”。

从抽取出的核心代码中可以很容易看出,参数 flag = False 时,变量 xxx 没有初始化就被 return xxx 语句调用。这也正是 ERROR 产生的原因,即 使用了未初始化的变量

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值