(免责声明:不是 Python child ,所以请温柔)
我正在尝试使用以下方法组合函数:
def compose(*functions):
return functools.reduce(lambda acc, f: lambda x: acc(f(x)), functions, lambda x: x)
对于标量函数,它按预期工作。我想使用返回元组的函数和其他接受多个参数的函数,例如。
def dummy(name):
return (name, len(name), name.upper())
def transform(name, size, upper):
return (upper, -size, name)
# What I want to achieve using composition,
# ie. f = compose(transform, dummy)
transform(*dummy('Australia'))
=> ('AUSTRALIA', -9, 'Australia')
由于
dummy
返回一个元组并且 transform
接受三个参数,我需要解压缩该值。如何使用上面的
compose
函数实现这一点?如果我这样尝试,我会得到:f = compose(transform, dummy)
f('Australia')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in <lambda>
File "<stdin>", line 2, in <lambda>
TypeError: transform() takes exactly 3 arguments (1 given)
有没有办法更改
compose
以便它在需要的地方解压? 最佳答案
这个适用于您的示例,但它不会处理任何任意函数 - 它仅适用于位置参数,并且(当然)任何函数的签名必须与前一个(wrt/应用程序顺序)的返回值匹配。
def compose(*functions):
return functools.reduce(
lambda f, g: lambda *args: f(*g(*args)),
functions,
lambda *args: args
)
请注意,在此处使用
reduce
虽然在函数式编程中肯定是惯用的,但相当不pythonic。 “明显的”pythonic 实现将使用迭代代替:def itercompose(*functions):
def composed(*args):
for func in reversed(functions):
args = func(*args)
return args
return composed
编辑:
你问“有没有办法让 compose 函数在两种情况下都可以工作”——“两种情况”在这里意味着函数是否返回可迭代的(你称之为“标量函数”,一个没有意义的概念在 Python 中)。
使用基于迭代的实现,您可以只测试返回值是否可迭代并将其包装在一个元组中,即:
import collections
def itercompose(*functions):
def composed(*args):
for func in reversed(functions):
if not isinstance(args, collections.Iterable):
args = (args,)
args = func(*args)
return args
return composed
但这并不能保证按预期工作 - 实际上,对于大多数用例,这甚至不能按预期工作。 Python 中有很多内置的可迭代类型(甚至更多是用户定义的),仅仅知道一个对象是可迭代的并不能说明它的语义。
例如
dict
或 str
是可迭代的,但在这种情况下显然应该被视为“标量”。 list
也是可迭代的,在这种情况下应该如何解释它实际上是无法确定的,而无需确切知道它包含什么以及组合顺序中的“下一个”函数期望什么 - 在某些情况下,您可能希望将其视为单个参数, 在其他情况下是 args 列表。IOW 只有
compose()
函数的调用者才能真正知道应该如何考虑每个函数结果 - 实际上,您甚至可能希望 tuple
被下一个函数视为“标量”值。所以长话短说:不,Python 中没有一刀切的通用解决方案。我能想到的最好的方法是将结果检查和组合函数的手动包装相结合,以便“组合”函数正确解释结果,但此时手动组合函数既简单又强大。FWIW 记得 Python 首先并且主要是一种动态类型的面向对象语言,因此虽然它确实对函数式编程习语有不错的支持,但它显然不是真正的函数式编程的最佳工具。
关于python - 函数组合、元组和解包,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47349538/