Python3函数内全局变量tokens报错:引用前未定义问题排查求助
报错原因
Python存在作用域查找规则,当你在函数内部对某个变量执行赋值类操作(包括+=、-=、直接赋值等)时,Python解释器会默认将该变量标记为函数内部的局部变量,不会再去外层作用域查找对应的变量。
你代码中的tokens是定义在全局作用域的变量,函数内的tokens += amount本质等价于tokens = tokens + amount,属于赋值操作,因此Python会将tokens识别为当前函数的局部变量,但你在读取赋值符号右侧的tokens时,局部作用域内还没有对该变量的定义,因此触发了“引用前未赋值”的报错。
另外你的代码还存在两处额外可修复的问题:
randint(1, 0)参数顺序错误,random.randint要求第一个参数小于等于第二个参数,需改为randint(0, 1)才能正常生成0或1的随机数input("double? ").lower漏了括号,lower是字符串方法,需要调用lower()才能得到小写的输入结果,否则你对比的是方法对象和字符串,永远返回False
解决方法
这里提供三种常见的修复方案:
方案1:添加global声明(快速修复)
在函数开头添加global tokens声明,明确告诉Python该变量使用全局作用域的定义,不要识别为局部变量。
修复后的代码示例:
from random import randint tokens = 100 def double_or_nothing(amount): global tokens if randint(0, 1) == 1: if input("double? ").lower() == "yes": amount *= 2 double_or_nothing(amount) else: tokens += amount else: tokens -= amount
方案2:用可变对象封装状态(避免global关键字)
可以将全局变量封装为可变对象(比如列表、字典),你修改的是可变对象内部的元素,而非对变量本身执行赋值操作,因此不会触发局部变量的识别逻辑:
from random import randint tokens = [100] # 用列表封装,列表是可变对象 def double_or_nothing(amount): if randint(0, 1) == 1: if input("double? ").lower() == "yes": amount *= 2 double_or_nothing(amount) else: tokens[0] += amount else: tokens[0] -= amount
方案3:取消全局变量,用参数传递和返回值处理状态(最推荐)
全局变量容易产生不可预知的副作用,更合理的写法是将状态作为参数传入函数,执行完成后返回新的状态,由外层代码更新:
from random import randint def double_or_nothing(amount, tokens): if randint(0, 1) == 1: if input("double? ").lower() == "yes": return double_or_nothing(amount * 2, tokens) else: return tokens + amount else: return tokens - amount # 调用示例 tokens = 100 tokens = double_or_nothing(10, tokens) print(tokens)
内容的提问来源于stack exchange,提问作者Hogu
相关产品推荐
相关产品推荐

