Идиоматическое применение аргументов к предоставленному словарю функций на основе выходных данных этих функций - PullRequest
0 голосов
/ 18 февраля 2019

Я ищу идиоматический способ оценки одной или нескольких функций на основе предоставляемых ими выходных данных с использованием входных данных, полученных из словаря «предварительно вычисленных» значений.

Я попытаюсь продемонстрировать это с рабочимпример.

Для запуска кода вам понадобится следующий импорт.Эти фрагменты представляют собой 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'), но не знаю, как еще это сделать,

Это решение выглядит приемлемым?Есть ли лучший способ присвоения функций значениям, которые они возвращают?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...