Я ищу идиоматический способ оценки одной или нескольких функций на основе предоставляемых ими выходных данных с использованием входных данных, полученных из словаря «предварительно вычисленных» значений.
Я попытаюсь продемонстрировать это с рабочимпример.
Для запуска кода вам понадобится следующий импорт.Эти фрагменты представляют собой Python 2.7 (у меня здесь нет выбора) - но в python 3 все должно работать, кроме getargspec (который, я считаю, называется getfullargspec или чем-то подобным).
import copy
from functools import partial
from inspect import getargspec # python 3.x uses something else?
По сути, у меня есть некоторые данные,что дорого вычислять:
defined_vars = {
'x': 2.0, # from some time consuming calculation
'y': 13.0,
}
На основе опций в других местах моей программы у меня есть несколько функций, которые получают одну или несколько записей этого словаря данных в качестве аргументов:
def f(x):
a = x + 1
return a
def g(y):
b = y / 2.0
return y
def h(x, y, power=2):
# c and d might be returned by the same expensive
# calculation
c = x + y
d = x * y**power
return (c, d)
Некоторыеиз этих функций могут возвращать отдельные значения и другие кортежи.Кроме того, могут быть ключевые аргументы, которые предоставляются за пределами defined_vars
, например power
в функции h
выше.
Моя программа генерирует список необходимых выходных данных, которыев основном дополнительные ключи, которые должны присутствовать в defined_vars
.На данный момент это кортеж:
required = ('a', 'b', ('c','d'))
Эти «требуемые» выходы должны соответствовать функции, возвращающей их.Следовательно, программное обеспечение (или пользователь с помощью опций) должно предоставлять словарь, соответствующий приведенным выше функциям значениям, которые они возвращают.
Текущее решение
На данный момент это выглядит так:
functions = {
'a' : f,
'b' : g,
('c', 'd') : partial(h, power=3),
}
Я сопоставляю аргументы с функциями, используя inspect.getargspec
(I знаю python2.7 скоро будет устаревшим, но у меня нет выбора, и я знаю, что python3.x имеет эквивалентную функциональность внутри проверки где-то) следующим образом:
def getArgs(function):
if type(function) is partial:
return getArgs(function.func)
argspec = getargspec(function)
if argspec.defaults:
return argspec.args[:-len(argspec.defaults)]
else:
return argspec.args
Я использую рекурсиютак что argspec будет работать с частично примененными функциями (я не буду частично применять ничего, кроме аргументов ключевых слов).
Я обертываю это в другую функцию, applyArgs
, чтобы извлечь требуемые аргументы из словарядоступные переменные, и применить их к функции в правильном положении:
def applyArgs(function, dict_of_vars):
arg_list = getArgs(function)
return function(*(dict_of_vars[arg] for arg in arg_list))
Наконец, я использую внешнюю функцию для перебора элементов required
, имеющих соответствующий ключ в functions
:
def assignToDict(required, functions, defined_vars):
for arg in functions.viewkeys() & required:
result = applyArgs(functions[arg], defined_vars)
if type(result) is tuple:
for k,v in zip(arg, result):
defined_vars[k] = v
else:
defined_vars[arg] = result
Что называется следующим образом (и изменяет defined_vars
на месте):
assignToDict(required, functions, defined_vars)
Мой вопрос :
Ядропроблема в том, что required
и functions
будутВ зависимости от других переменных времени выполнения в другом месте программы, и я хотел бы сохранить гибкость, чтобы указать различные способы вычисления required
(назначая различные функции для functions
).
В частности, я хотел бырешение должно быть простым, так что пользователи могут указывать свои собственные functions
словари (переданные в качестве аргумента функции более высокого уровня), а мое решение чувствует неуклюжим: мне не нравится указывать наборы результатовв качестве ключей (например, ('c', 'd')
) в required
, поскольку это кажется ограничительным (иногда я мог бы захотеть иметь одну функцию, возвращающую 'c', и другую функцию, возвращающую 'd'), но не знаю, как еще это сделать,
Это решение выглядит приемлемым?Есть ли лучший способ присвоения функций значениям, которые они возвращают?