Python 中的条件函数链接
Conditional function chaining in Python
假设有一个函数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 个)。
我找到了一种使用装饰器的解决方案。看看:
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
函数时检查一次,调用时不检查。
我能想到的结构最相似的代码必须按以下方式构建,您的 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)
Returns:
# Assume cond1..3 are all True
17 # (2**3*2+1)
假设有一个函数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 个)。
我找到了一种使用装饰器的解决方案。看看:
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
函数时检查一次,调用时不检查。
我能想到的结构最相似的代码必须按以下方式构建,您的 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)
Returns:
# Assume cond1..3 are all True
17 # (2**3*2+1)