Flask结合APScheduler时如何在上下文外更新app全局字典?
问题原因
old_dic = new_dic写法不生效是Python参数传递机制导致的:将app.dictionary传入函数时,函数内的old_dic只是指向原字典的局部引用,执行该赋值语句只会修改局部引用的指向,完全不会改动app实例上绑定的原字典属性,因此外部访问到的始终是旧值。而old_dic[key] = xxx、old_dic.update()这类操作是直接修改局部引用指向的原字典对象本身,所以修改可以正常生效。
实现方案
两种方案都可以实现字典的全量更新,按需选择即可:
方案1:直接导入app实例操作(推荐)
不通过参数传递字典,直接在updater模块导入Flask app实例,直接操作app.dictionary属性,从根源避开引用传递的问题。
代码调整如下:
app.py
import gevent.monkey gevent.monkey.patch_all() from flask import Flask from apscheduler.schedulers.background import BackgroundScheduler # app初始化移到判断块外,保证其他模块可以正常导入 app = Flask(__name__) app.dictionary = {} if __name__=='__main__': app.scheduler = BackgroundScheduler(daemon=True) # 定时任务不需要额外传递字典参数 app.scheduler.add_job('updater:Updater.update', ... ) app.scheduler.start() app.run(...)
updater.py
from app import app class Updater: @classmethod def update(cls): # 执行业务逻辑生成新字典 new_dic = { ... } # 两种更新方式都可以生效 # 方式1:原地清空后填充新内容 app.dictionary.clear() app.dictionary.update(new_dic) # 方式2:直接替换属性绑定的对象 # app.dictionary = new_dic
注意:如果有并发读字典的场景,更新时建议加轻量锁,避免读取到半更新状态的脏数据。
方案2:原地修改字典内容,不做对象替换
如果不想调整app导入逻辑,就不要做old_dic = new_dic的对象替换操作,改为清空原字典后全量填充新字典的键值对,本质和单键修改的逻辑一致:
updater.py
class Updater: @classmethod def update_dict(cls, old_dic, new_dic): # 清空原字典内容,填充新字典的所有键值 old_dic.clear() old_dic.update(new_dic) @classmethod def update(cls, old_dic): # 执行业务逻辑生成new_dic new_dic = { ... } cls.update_dict(old_dic, new_dic)
这种方案不需要修改现有app.py的传参逻辑,但要注意所有对字典的修改都必须基于原对象操作,不能出现重新赋值变量的写法。
内容的提问来源于stack exchange,提问作者sjpark
相关产品推荐
相关产品推荐

