Python: декоратор для отложенного вызова функции
Отказ от ответственности: я довольно новичок в python (2 месяца)
У меня есть скрипт, который должен автоматически генерировать нагрузку тестов, и прежде чем делать свое дело, ему нужно проанализировать некоторые данные из конфигурационных файлов. Дело в том, что некоторые из этих данных могут быть известны только позже, когда все конфигурации были прочитаны, проанализированы и обработаны. Мое текущее решение состоит в том, чтобы заполнить файл функциями вида:
def Foo (arg1, arg2, ..., argn) :
return lambda **kwargs : Foo_helper(arg1, arg2, ..., argn, refs = kwargs["refs"], vars = kwargs["vars"])
def Foo_helper(arg1, arg2, ..., argn, **kwargs) :
... some function statements ...
Где я праймирую args от 1 до n, потому что скрипт не знает, какие функции он выполняет зовущий. Это работает, но я ненавижу необходимость определять 2 функции, чтобы иметь возможность вызывать только 1. Мне бы хотелось что-то вроде:
@deferred
def Foo_helper(arg1, arg2, ..., argn, **kwargs) :
... some function statements ...
Но моя попытка пока что формы:
def arg_deferred(fns) :
def newFn(*args, **kwargs) :
fn(*args, **kwargs)
return lambda **kwargs : newFn(*args, kw1 = kwargs["vars"], kw2 = kwargs["refs"], ..., kwn = kwargs["kwn"])
Достает меня ...
return lambda *args, **kwargs : newFn(*args, refs = kwargs["refs"], vars = kwargs["vars"])
KeyError: 'refs'
И это происходит в том месте, где я называю Фу. Я не могу понять, почему это происходит, потому что в тот момент, когда я звоню Foo, я только ожидаю получить обратно лямбду, которая при вызове позже вызовет newFn, а не на самом деле вызовет newFn немедленно. Делаю ли я что-то, что для более опытных пользователей python очевидно, есть ли лучший способ получить то, что я хочу? (Я пытался дать вместо возврата, но не нашел способа заставить это работать, и у меня была игра с functools partial, но я обнаружил, что вызываю функцию с пустыми кваргами)
1 ответ:
Похоже, что, возможно, то, что вы хотите, - это
functools.partialдекоратор. Он делает именно то, что делает ваша функцияFoo, но в более общем виде.Основываясь на вашем комментарии, вы также можете использовать класс, чтобы делать то, что вы хотите, который может быть немного более питонским:
class FooHelper(object): def __init__(self, arg1, arg2, ..., argn): self.arg1 = arg1 self.arg2 = arg2 ... self.argn = argn def __call__(self, **kwargs): # ... some function statements ... foo_helper_inst = FooHelper(conf_arg1, conf_arg2, ..., conf_argn) foo_helper_inst(refs = 10, vars = 2)На самом деле, после дальнейшего размышления, наиболее пифонический способ сделать это-создать класс, который представляет вашу конфигурацию, содержащую все методы, которые вам нужны. Что-то например:
class Config(object): def __init__(self, arg1, arg2, ..., argn): self.arg1 = arg1 self.arg2 = arg2 ... self.argn = argn def foo_helper(self, **kwargs): # ... some function statements ... def foo_helper2(self, **kwargs): # ... some function statements 2 ... # ... def bar_helper(self, **kwargs): # ... some function statements ... a = Config(conf_arg1, conf_arg2, ..., conf_argn) a.foo_helper(refs = 10, vars = 2) a.foo_helper2(foo = 1, baz = 2) a.bar_helper(goo=3)И вы можете передать эти методы как вызываемые:
def do_something(foo_func): foo_func(refs=10, vars=2) do_something(a.foo_helper)
Comments