По сути, я хочу поместить переменную в стек, которая будет доступна всем вызовам ниже этой части в стеке, пока блок не выйдет. В Java я решил бы это, используя статический поток, локальный с методами поддержки, к которым затем можно было получить доступ из методов.
Типичный пример: вы получаете запрос и открываете соединение с базой данных. Пока запрос не будет выполнен, вы хотите, чтобы весь код использовал это соединение с базой данных. После завершения и закрытия запроса вы закрываете соединение с базой данных.
Для этого мне нужен генератор отчетов. Каждый отчет состоит из нескольких частей, каждая часть может опираться на разные вычисления, иногда разные части частично опираются на одни и те же вычисления. Поскольку я не хочу повторять тяжелые вычисления, мне нужно их кешировать. Моя идея - украсить методы с помощью кеш-декоратора. Кэш создает идентификатор на основе имени метода и модуля и его аргументов, смотрит, рассчитал ли он все это уже в переменной стека, и выполняет метод, если нет.
Я попытаюсь уточнить, показывая мою текущую реализацию. Хочу, чтобы я хотел сделать, это упростить код для тех, кто осуществляет вычисления.
Во-первых, у меня есть объект доступа к центральному кешу, который я называю MathContext:
class MathContext(object):
def __init__(self, fn):
self.fn = fn
self.cache = dict()
def get(self, calc_config):
id = create_id(calc_config)
if id not in self.cache:
self.cache[id] = calc_config.exec(self)
return self.cache[id]
Аргумент fn - это имя файла, относительно которого создается контекст, из которого можно считывать данные для вычисления.
Тогда у нас есть класс вычисления:
class CalcBase(object):
def exec(self, math_context):
raise NotImplementedError
А вот и глупый пример Фибоначчи. Ни один из методов на самом деле не является рекурсивным, вместо этого он работает с большими наборами данных, но он показывает, как вы будете зависеть от других вычислений:
class Fibonacci(CalcBase):
def __init__(self, n): self.n = n
def exec(self, math_context):
if self.n < 2: return 1
a = math_context.get(Fibonacci(self.n-1))
b = math_context.get(Fibonacci(self.n-2))
return a+b
То, что я хочу вместо Фибоначчи, это просто декорированный метод:
@cache
def fib(n):
if n<2: return 1
return fib(n-1)+fib(n-2)
В примере с math_context, когда math_context выходит из области видимости, то же происходит и со всеми его кэшированными значениями. Я хочу то же самое для декоратора. То есть. в точке X все кэшированное @cache разыменовывается для привязки.