- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
考虑以下关于函数组合的 Python 片段:
from functools import reduce
def compose(*funcs):
# compose a group of functions into a single composite (f(g(h(..(x)..)))
return reduce(lambda f, g: lambda *args, **kwargs: f(g(*args, **kwargs)), funcs)
### --- usage example:
from math import sin, cos, sqrt
mycompositefunc = compose(sin,cos,sqrt)
mycompositefunc(2)
我有两个问题:
compose
“操作逻辑”? (它是如何工作的?)我已经看了here , here和 here too ,我的问题是不理解lambda
的含义或reduce
的含义(我想我得到了,例如,2
在用法示例中将是 funcs
中要组合的第一个元素)。我发现更难理解的是两个 lambda
是如何组合/嵌套并与 *args, **kwargs
混合的复杂性,这里是 reduce
第一个参数 ...
编辑:
首先,@Martijn 和@Borealid,感谢你们的努力和回答,感谢你们为我付出的时间。 (很抱歉耽误了,我是在业余时间做的,并不总是有很多......)
好吧,现在来谈谈事实......
关于我的问题的第一点:
在此之前,我意识到我并没有真正了解(但我希望我现在已经了解)那些*args, **kwargs
可变参数之前是至少 **kwargs
不是强制性的(我说的好吧?)这让我明白了,例如,为什么 mycompositefunc(2)
只使用一个(非关键字)传递的参数。
然后我意识到,即使将内部 lambda 中的那些 *args、**args
替换为简单的 x
,该示例也可以正常工作。我想那是因为,在示例中,所有 3 个组合函数(sin、cos、sqrt
)都需要一个(而且只有一个)参数……当然,返回一个结果……所以,更具体地说,它起作用是因为第一个组合函数只需要一个参数(后面的其他函数自然在这里只得到一个参数,这是前面组合函数的结果,所以你不能编写在第一个参数之后期望有多个参数的函数......我知道这有点扭曲但我认为你明白了我想要解释的......)
现在来谈谈对我来说真正不清楚的事情:
lambda f, g: lambda *args, **kwargs: f(g(*args, **kwargs))
lambda 嵌套“魔法”是如何运作的?
怀着你应得的所有崇高的敬意,我对你表示敬意, 在我看来,你们两个得出的结论都是错误的,最终结果应为:sqrt(sin(cos(*args, **kw)))
。其实不可能,sqrt函数的使用顺序显然是颠倒的:不是最后一个组合,而是第一个组合。
我这样说是因为:
>>> mycompositefunc(2)
0.1553124117201235
它的结果等于
>>> sin(cos(sqrt(2)))
0.1553124117201235
而你得到一个错误
>>> sqrt(sin(cos(2)))
[...]
ValueError: math domain error
(这是由于试图平方根负 float )
#P.S. for completeness:
>>> sqrt(cos(sin(2)))
0.7837731062727799
>>> cos(sin(sqrt(2)))
0.5505562169613818
所以,我知道函数组合将从最后一个到第一个(即:compose(sin,cos,sqrt) => sin(cos(sqrt(x))))但是“为什么?”和lambda 嵌套“魔法”是如何工作的? 对我来说仍然有点不清楚...非常感谢帮助/建议!
关于第二点(关于重写 compose without reduce)
@Martijn Pieters:您的第一个撰写(“包装”的)工作并返回完全相同的结果
>>> mp_compfunc = mp_compose(sin,cos,sqrt)
>>> mp_compfunc(2)
0.1553124117201235
不幸的是,展开的版本会循环直到 RuntimeError: maximum recursion depth exceeded
...
@Borealid:您的 foo/bar 示例不会获得超过两个组合函数,但我认为这只是为了解释而不是为了回答第二点,对吧?
最佳答案
lambda
签名和调用语法中的 *args, **kw
语法是传递任意参数 的最佳方式。他们接受任意数量的位置和关键字参数,并将它们传递给下一个调用。您可以将外部 lambda
的结果写为:
def _anonymous_function_(*args, **kw):
result_of_g = g(*args, **kw)
return f(result_of_g)
return _anonymous_function
compose
函数可以在没有 reduce()
的情况下重写,如下所示:
def compose(*funcs):
wrap = lambda f, g: lambda *args, **kw: f(g(*args, **kw))
result = funcs[0]
for func in funcs[1:]:
result = wrap(result, func)
return result
这与 reduce()
调用完全相同;为函数链调用 lambda。
因此,序列中的前两个函数是 sin
和 cos
,它们被替换为:
lambda *args, **kw: sin(cos(*args, **kw))
然后将其作为 f
传递给 next 调用,使用 sqrt
g
,因此您得到:
lambda *args, **kw: (lambda *args, **kw: sin(cos(*args, **kw)))(sqrt(*args, **kw)))
可以简化为:
lambda *args, **kw: sin(cos(sqrt(*args, **kw)))
因为 f()
是一个将其参数传递给嵌套的 sin(cos())
调用的 lambda。
最后,您生成了一个调用 sqrt()
的函数,其结果被传递给 cos()
,而该函数的输出然后传递给 sin()
。 *args, **kw
允许您传入任意数量的参数或关键字参数,因此 compose()
函数可以应用于任何 当然,than 是可调用的,前提是除了第一个函数之外的所有函数都只接受一个参数。
关于python - 这个特定的 Python 函数组合背后的逻辑是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31893096/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!