钩子每个变量引用和执行代码



我有一个Python应用程序拆分在不同的文件。其中之一,models.py,在PyQt5表模型中包含了从几个PyQt5表单文件引用的几个映射:

# first lines:
agents_id_map = 
{agent.name:agent.id for agent in db.session.query(db.Agent, db.Agent.id)}
# ....
# 2000 thousand lines 

我想把这种地图集中在一个点上。我也在使用SQLAlchemy。Agent类在db.py文件中定义。我使用这些映射来实现另一个对象(比如发票)中的外键,如:

invoice = db.Invoice()
# Here is a reference
invoice.agent_id = models.agents_id_map[agent_combo.currentText()]
····
db.session.add(invoice) 
db.session.commit() 

问题是model.py模块被缓存,并且应用程序的几个部分访问旧数据,并且,如果应用程序的另一个运行实例A创建了一个新的代理,并且运行实例B想要创建一个新的发票,运行实例B将不会看到A创建的新代理,除非重新启动应用程序。如果同一运行实例中的用户创建了一个代理,然后他想要创建发票,也会发生这种情况。我的解决方案是:

  • 重新加载模块,以再次执行整个代码,但这可能非常昂贵。
  • 将构建这些映射的代码隔离在另一个文件中,比如maps.py,这样重新加载和修改所有通过重构引用它的代码的成本会更低。

是否有一种解决方案,允许我只触摸构建这些地图的代码,而应用程序的其余部分仍然对更改一无所知,并且每次从另一个模块引用地图甚至相同,代码被执行,有效地重新构建具有新数据的地图?

是否有一种解决方案,允许我只触摸构建这些地图的代码,而应用程序的其余部分仍然对更改一无所知,并且每次从另一个模块引用地图甚至相同,代码得到执行,有效地重新构建具有新数据的地图?

当然:把你的映射放在一个函数中,或者更好的是,放在一个类中。

如果我正确理解这个问题,你有状态数据(映射)需要在某些条件下重新生成(每次访问它们?或者只是在每次更新数据库时?)。我会这样做:


class Mappings:
def __init__(self, db):
self._db = db
... # do any initial db stuff you need to here

def id_map(self, thing):
db_thing = getattr(self._db, thing.title)
return {x.name:x.id for x in self._db.session.query(db_thing, db_thing.id)}
def other_property_map(self, prop):
... # etc
mapping = Mapping(db)
mapping.id_map("agent")

这里假设您给出的映射示例是您的主要用例,但是这个模型可以很容易地适用于您可能需要的几乎任何其他映射。

你可以为你需要的每一种"映射"写一个方法,它会返回你想要的字典。请注意,这里我假设您在其他地方设置了db,并将一个完全初始化的db访问对象传递给类,这可能是您想要做的——这个类只是封装映射器状态,而不是重新创建窗体。

缓存没有提供任何缓存。但是,如果您完全控制了db,那么在执行任何db提交之前运行钩子以查看是否触及了任何特定的模型,然后声明这些模型需要重新构建是很容易的。像这样:

class DbAccess(Mappings):
def __init__(self, db, models):
super().init(db)
self._cached_map = {model: {} for model in models}
def db_update(model: str, params: dict):
try:
self._cached_map[model] = {} # wipe cache
except KeyError:
pass
self._db.update_with_model(model, params) # dummy fn
def id_map(self, thing: str):
try:
return self._cached_map[thing]["id"]
except KeyError:
self._cached_map[thing]["id"] = super().id_map(thing)
return self._cached_map[thing]["id"]

我不真的认为DbAccess应该继承映射——把它都放在一个类中,或者有一个DB类和一个Mappingsmixin,并从两者继承。我只是不想把所有的东西都写出来。

我没有写任何真正的db访问例程,(因此我的虚拟fn),因为我不知道你是怎么做的(但显然使用ORM)。但其基本思想是自己处理缓存,每次存储映射,但每次执行涉及相关模型的提交事务时删除所有存储的映射(从而根据需要重新构建缓存)。

除了

注意,如果你真的有2000行手工声明的thing.name: thing.id形式的映射,你真的应该在运行时生成它们。声明性很好,但是写出同样的东西的2000种排列并不是声明性的,它只是很耗时——在启动时完成一个简单的循环将数据放入ram就可以了。

最新更新