Python3 Dash回调修改全局变量触发未解析引用报错的原因及解决方法
问题成因
该问题完全由Python本身的变量作用域规则导致,和Dash框架没有直接关联:
- 只读变量时没有报错的原因:如果函数内部只有对某变量的读取操作、没有赋值操作,Python解析器会自动向上层作用域搜索该变量。你初始的代码中
update函数仅读取fff做打印,所以可以正常读取到全局作用域定义的fff变量。 - 加了赋值操作后报错的原因:只要函数内部出现了对某变量的赋值操作(无论赋值语句在读取操作之前还是之后),Python会直接将该变量标记为函数局部变量。你修改后的代码里有
fff = True的赋值逻辑,解析器默认fff是update的局部变量,但你在赋值之前就执行了打印操作,局部变量还未完成定义,因此抛出未定义引用报错。 nonlocal报错的原因:nonlocal关键字仅用于访问嵌套函数外层的非全局作用域变量,你的fff是定义在模块顶层的全局变量,不属于任何外层嵌套函数的作用域,因此会提示找不到对应绑定。
解决方案
你可以根据使用场景选择以下任意一种方案:
- 方案1:用
global关键字声明全局变量
直接在update函数开头声明你要操作的是全局作用域的fff,即可正常读写:@app.callback( Output('mydiv', '...'), Input('mydiv', 'myevent') ) def update(evt): global fff print(fff) fff = True return dash.no_update - 方案2:将状态存入可变对象
可变对象(字典、列表、类实例等)修改内部属性不需要重新赋值,不会触发局部变量标记,无需额外关键字即可直接操作:# 顶层定义用字典存储状态 state = {"fff": False} @app.callback( Output('mydiv', '...'), Input('mydiv', 'myevent') ) def update(evt): print(state["fff"]) state["fff"] = True return dash.no_update - 方案3:使用Dash官方推荐的状态存储方案
自定义全局变量在Dash多进程/多worker部署时会出现状态不同步的问题,更稳妥的做法是用dcc.Store组件将状态存在前端,回调中读写该组件的数据即可:app.layout = html.Div([ dcc.Store(id='state-store', data={'fff': False}), html.Div(id='mydiv', ...) ]) @app.callback( Output('mydiv', '...'), Output('state-store', 'data'), Input('mydiv', 'myevent'), State('state-store', 'data'), prevent_initial_call=True ) def update(evt, state_data): print(state_data['fff']) state_data['fff'] = True return dash.no_update, state_data
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

