Python开发Telegram Bot时嵌套函数调用报UnboundLocalError
问题原因
这个报错和普通变量触发的UnboundLocalError遵循完全一致的Python作用域规则,不存在函数特殊的情况:
- Python在解析函数体时,会将所有在函数内被赋值/定义的名称标记为当前函数作用域的局部变量,不会向外层作用域查找
- 函数定义本质是给名称赋值的操作,你写的
def printmsg(text): ...等价于给当前作用域的printmsg变量绑定一个函数对象 - 你的代码里所有对
printmsg的调用都写在了printmsg定义语句的前面,代码从上到下执行到调用行时,局部变量printmsg还没有被赋值,就触发了“引用前未赋值”的错误。
另外你的代码还存在一个隐藏的前置报错点:reply函数的入参写了adopo_list=adopo_list,但全局作用域并没有定义adopo_list,你全局定义的回复告别消息的列表叫goodbye_list,就算修了printmsg的位置问题,这里也会触发NameError。
修复方法
- 最小改动方案:把
printmsg的嵌套函数定义移动到reply函数内所有调用逻辑的最前面,同时修正入参里adopo_list绑定的全局变量名。修正后的核心代码如下:
# This function has to choose the appropriate way to reply to the user, based on what he/she wrote def reply(update, context, ciao_counter=0, ciao_list=ciao_list, greatings_list=greatings_list, adopo_list=goodbye_list, eh_list=eh_list): # 先定义printmsg,再执行后续调用逻辑 def printmsg(text): update.message.reply_text(text) msg = update.message.text.lower() match msg: case msg if msg in greatings_list: match ciao_counter: case 0: printmsg(choice(ciao_list)) ciao_counter += 1 case 1: printmsg('Mi hai già salutato, non serve che lo fai di nuovo') ciao_counter += 1 case 2: printmsg('Mi. hai. gia. salutato.') ciao_counter += 1 case 3: printmsg('Basta, non ti rispondo più') ciao_counter += 1 case _: printmsg('...') case msg if 'a dopo' in msg: printmsg(choice(adopo_list)) ciao_counter = 0 case _: printmsg(choice(eh_list))
- 可选优化方案:如果后续多个处理函数都要用到快捷发消息的逻辑,可以把
printmsg提到全局作用域定义,不需要每个处理函数里都嵌套定义,减少重复代码。
附加提示:你当前把
ciao_counter设为函数默认参数的写法存在逻辑隐患,Python函数的默认参数在函数定义时就会被初始化,所有调用reply的请求会共享同一个计数器变量,不会按你预期的每个用户单独计数。如果要做用户维度的计数,需要把计数存在context.user_data这类独立的存储里,这个不属于本次报错的范畴,按需调整即可。
内容的提问来源于stack exchange,提问作者Riccardo Zampieri
相关产品推荐
相关产品推荐

