Python递归函数变量作用域混淆引发UnboundLocalError问题咨询
报错的核心根源
这个问题和递归的变量隔离特性没有关系,本质是代码存在未对局部变量赋值就直接访问的执行分支,我们可以走查一遍实际的执行流程就能完全理清楚:
- 首次调用最外层
my_function()时,如果输入了非整数,int()转换会直接抛出ValueError,此时try块里的赋值语句number = int(...)完全没有执行——也就是说,最外层函数的作用域里,number这个变量从来没有被创建过。 - 代码进入except分支后,只是执行了递归调用
my_function(),既没有把递归调用的返回值存入当前作用域的number变量,也没有直接返回这个递归结果,而是让当前函数继续顺序往下走。 - 内层递归的函数拿到合法的整数输入、成功走完赋值流程并返回结果后,最外层的函数会继续走到自己末尾的
return number语句。此时检查最外层作用域的number,发现这个变量从来没有被赋值过,自然就抛出了UnboundLocalError。
你之前的认知偏差在这里:你以为每次递归的执行层都会走完number的赋值流程,但实际上只要某一层的int()转换抛错,这一层的number就从来不会被创建——只是这一层当时卡在内层递归的调用上,没来得及走到末尾的return语句触发报错而已。
为什么把
return number移入try块就能正常运行 调整return位置的逻辑非常直接:只要代码在try块里成功执行了number = int(...)的赋值操作,就立刻触发return,根本不会走到函数外层的代码段,从执行路径上完全规避了“访问未赋值number”的错误场景。
补充:哪怕不把
return number移入try块,只要把except分支的代码改成return my_function(),程序也能正常运行——因为这样所有的返回路径都有明确的返回值,不会出现走到函数末尾时变量未绑定的情况。
原代码的问题可以通过标注直观看到:
def my_function(): try: number = int(input("What is your favorite number?\n\n")) except ValueError: # 这里递归的返回值被直接丢弃,没有存入当前作用域的number my_function() # 抛错的执行层从来没给number赋过值,执行到这行就会触发报错 return number
内容的提问来源于stack exchange,提问作者James Carter
相关产品推荐
相关产品推荐

