我有一个复杂的 python 函数,它根据各种子函数和数据依赖性来计算级别。
控制数据依赖性并进行可重复计算的最佳方法是什么?
数据可以来自外部数据库和数据源,因此当代码多次运行时它们可能会发生变化。
目前我正在使用以下方法:将所有数据访问包装到一个访问器类中,该类缓存它请求的所有数据。访问器对象是一个全局变量,因此在计算结束时我可以查找缓存的状态。
这给了我可重复性:如果我想使用完全相同的数据重新运行计算,我只需强制访问器函数直接从缓存中检索数据。
一个缺点是这种方法强制使用全局变量。
另一种方法是将数据依赖项直接注入到函数参数中,但我不预先知道依赖项甚至它们的结构,因为我的代码中的分支可能依赖于数据。
有人知道该主题的更好替代方案或参考吗?
谢谢你
装饰,装饰,装饰。尤其是在 Python 中 - 或多或少有原生支持。
但是,这不是缓存。事实上,您将某些内容存储在 RAM 中并避免可能会读取更新数据的进一步调用,这一事实不足以将其称为“缓存”。后者——不多也不少——是一种优化机制;它有助于保持系统性能足够好——仅此而已。相反,您正在讨论随时可能发生变化的并发系统上下文中的状态初始化问题。
从你写的内容我推断你缺乏背景。由于您明确地将您的任务标记为与
functional-programming
相关,因此我将重点关注其常识和公认的模式。
首先想到的是Haskell。两者都是因为类型类(Python 中不存在类型类,您不应该尝试自己实现它们,这会破坏该语言的哲学,并且不会与其他库很好地配合)。然而哈斯克尔仍然是富有洞察力的灵感来源。在那里你会得到一个 State Monad™ 和一个
do
符号,它允许你实现你的目标,同时避免全局状态:你只需执行一个 IO
(在另一个 monad 内),然后初始化你的 (非全局)状态 monad 实例并确保其余计算在其上下文中运行。我想象的最接近 Python 原生的东西是类似的:
with MyDataContext(...) as dc:
state = dc.read_state() # makes sure to read the right data
...
这不一定是全局的,但可以让您将代码保留在给定的数据上下文中(无论它对我一无所知的领域可能意味着什么)。
另一种方法是普通的旧装饰。给定一个执行一些 IO 并通过网络检索字节的函数
get_data()
,您可以实现一个简单的装饰器,例如
once(get_data)
,它将生成另一个函数 相同的接口,但行为略有不同 - 即,短- 循环后续呼叫。此类典型的 Python 代码看起来有些相似:
import functools
import time
import requests # pip3 install requests
@functools.cache
def get_data(num):
res = requests.get('google.com')
return res.body
然后你的装饰器可以变得任意聪明:例如,没有什么可以阻止你检查函数的参数并据此采取不同的行动。另一个典型的策略是考虑您运行的环境,并通过生成更多日志并将整个数据快照序列化到持久存储以供将来重用,从而在调试/测试模式下表现不同。请注意,装饰器很容易自行测试 - 欢迎您毫不费力地使用
get_data
来模拟
get_fake_data
并确保您的装饰器完成工作。