Условное связывание функций в Python - PullRequest
4 голосов
/ 12 марта 2019

Представьте себе, что есть функция g, которую я хочу реализовать путем объединения подфункций.Это может быть легко сделано:

def f1(a):
    return a+1

def f2(a):
    return a*2

def f3(a):
    return a**3

g = lambda x: f1(f2(f3(x)))

Однако, теперь рассмотрим, что, какие подфункции будут связаны вместе, зависит от условий: в частности, от заданных пользователем опций, которые известны заранее.Конечно, можно сделать:

def g(a, cond1, cond2, cond3):

    res = a
    if cond1:
        res = f3(res)
    if cond2:
        res = f2(res)
    if cond3:
        res = f1(res)
    return res

Однако вместо того, чтобы динамически проверять эти статические условия каждый раз, когда вызывается функция, я предполагаю, что лучше определить функцию g на основе ее составляющих функций заранее.,К сожалению, следующее дает RuntimeError: maximum recursion depth exceeded:

g = lambda x: x
if cond1:
    g = lambda x: f3(g(x))
if cond2:
    g = lambda x: f2(g(x))
if cond3:
    g = lambda x: f1(g(x))

Есть ли хороший способ выполнить эту условную цепочку в Python?Обратите внимание, что связываемые функции могут иметь значение N, поэтому нельзя отдельно определять все 2 ^ N комбинаций функций (в данном примере 8).

Ответы [ 2 ]

4 голосов
/ 12 марта 2019

Я нашел одно решение с использованием декораторов. Посмотрите:

def f1(x):
    return x + 1

def f2(x):
    return x + 2

def f3(x):
    return x ** 2


conditions = [True, False, True]
functions = [f1, f2, f3]


def apply_one(func, function):
    def wrapped(x):
        return func(function(x))
    return wrapped


def apply_conditions_and_functions(conditions, functions):
    def initial(x):
        return x

    function = initial

    for cond, func in zip(conditions, reversed(functions)):
        if cond:
            function = apply_one(func, function)
    return function


g = apply_conditions_and_functions(conditions, functions)

print(g(10)) # 101, because f1(f3(10)) = (10 ** 2) + 1 = 101

Условия проверяются только один раз при определении функции g, они не проверяются при ее вызове.

2 голосов
/ 12 марта 2019

Наиболее структурно похожий код, который я могу придумать, должен быть структурирован следующим образом, ваш f1.. f3 должен стать псевдо-декоратором, например:

def f1(a):
    def wrapper(*args):
        return a(*args)+1
    return wrapper

def f2(a):
    def wrapper(*args):
        return a(*args)*2
    return wrapper

def f3(a):
    def wrapper(*args):
        return a(*args)**3
    return wrapper

И затем вы можете применить этидля каждой функции.

g = lambda x: x
if cond1:
    g = f3(g)
if cond2:
    g = f2(g)
if cond3:
    g = f1(g)
g(2)

Возвращает:

# Assume cond1..3 are all True
17 # (2**3*2+1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...