In [1]: add1 = lambda x : x+1 In [2]: add1 Out[2]: <function __main__.<lambda>(x)> In [3]: add1(1) Out[3]: 2
add1是一个函数类型
In [4]: add2 = lambda x : lambda y, z : x+y+z In [5]: add2 Out[5]: <function __main__.<lambda>(x)> In [6]: add2(1) Out[6]: <function __main__.<lambda>.<locals>.<lambda>(y, z)> In [7]: add2(1)(2,3) Out[7]: 6
add2和add2(1)都是函数类型,lambda函数从外层向内层解析,若先传入两个参数则报错,解析完第一层返回的仍然是一个函数。
In [8]: import functools In [9]: def compose(*functions): ...: return functools.reduce(lambda f,g : lambda x:g(f(x)), functions, lambda x : x) ...: ...: In [10]: compose(lambda x:2*x) Out[10]: <function __main__.<lambda>(x)> In [11]: compose(lambda x:2*x)(1) Out[11]: 2 In [12]: compose(lambda x:2*x, lambda x: 3*x) Out[12]: <function __main__.compose.<locals>.<lambda>.<locals>.<lambda>(x)> In [13]: compose(lambda x:2*x, lambda x: 3*x)(1) Out[13]: 6
functools.reduce函数有三个位置参数,第一个是函数;第二个是可迭代对象;第三个是参数的初始值,可以不设定。reduce函数一次可以从可迭代对象中传入两个值,前两个参数经过函数运算得到的结果作为第一个参数,再传入可迭代对象中的第三个参数,依次执行下去,直到可迭代对象完成迭代,得到结果。
In [14]: def compose_1(*functions): ...: return functools.reduce(lambda f,g : lambda x:g(f(x)), functions, lambda x : x+1) ...: ...: In [15]: compose_1(lambda x:2*x) Out[15]: <function __main__.compose_1.<locals>.<lambda>.<locals>.<lambda>(x)> In [16]: compose(lambda x : x+1, lambda x:2*x) Out[16]: <function __main__.compose.<locals>.<lambda>.<locals>.<lambda>(x)> In [17]: compose_1(lambda x:2*x)(1) Out[17]: 4 In [18]: compose(lambda x : x+1, lambda x:2*x)(1) Out[18]: 4 In [19]: compose_1(lambda x:2*x, lambda x: 3*x) Out[19]: <function __main__.compose_1.<locals>.<lambda>.<locals>.<lambda>(x)> In [20]: compose(lambda x : x+1, lambda x:2*x, lambda x: 3*x) Out[20]: <function __main__.compose.<locals>.<lambda>.<locals>.<lambda>(x)> In [21]: compose_1(lambda x:2*x, lambda x: 3*x)(1) Out[21]: 12 In [22]: compose(lambda x : x+1, lambda x:2*x, lambda x: 3*x)(1) Out[22]: 12
用compose和compose_1对比只想说明,添加初始化项(第三个参数),就相当于在可迭代对象的最前方加入这个初始化项。
In [23]: def compose_2(*functions): ...: return functools.reduce(lambda f,g : lambda x:f+g+x, functions) ...: ...: In [24]: compose_2(1) Out[24]: 1 In [25]: compose_2(2) Out[25]: 2 In [26]: compose_2(lambda x:2*x) Out[26]: <function __main__.<lambda>(x)> In [27]: compose_2(lambda x:2*x)(1) Out[27]: 2
通过compose和compose_2对比,想说明,如果传入的可迭代对象只有一个参数,那么将只会原样输出,与之后的内层函数将没有关系,所以需要传入第三个位置参数
In [28]: def compose_3(*functions): ...: return functools.reduce(lambda f,g : lambda x:f+g+x, functions, 1) ...: ...: In [29]: compose_3(1) Out[29]: <function __main__.compose_3.<locals>.<lambda>.<locals>.<lambda>(x)> In [30]: compose_3(1)(1) Out[30]: 3
以上就是传入了第三个位置参数,当可迭代对象只有一个参数时,也可正常计算。
这是第二次梳理这个知识点,之前写过博客,但是长久不用忘了,就重新梳理整理了思路。如果这篇介绍的不清楚可以结合上一篇理解。