如何把一个功能在一行代码里面实现
学习资料
几前年看过酷壳的这两篇文章, 当时以为已经掌握了. 现在又想实践一下的时候, 发现完全不知道怎么写了. 所以温习并记录一下.
步骤(套路)
可以认为, 如何把一个功能在一行代码里面实现, 是有固定的套路的.
我还不能马上理解里面的原因原理, 所以自认为是套路, 其实是我自己太弱.
分下面4个步骤, 看不懂也没关系, 下面有例子具体演示说明
- 用递归实现此功能
- 将递归函数做为参数传入调用函数(是我写不清楚, 具体看下面例子)
- 使用匿名函数替换(是我写不清楚, 具体看下面例子)
- 高阶函数(是我写不清楚, 具体看下面例子)
例子一 求阶乘
步骤1 递归实现阶乘
求阶乘用递归还是很自然的, 如下
def fact(n):
return 1 if n==0 else fact(n-1)*n
print(fact(5))
步骤2
def fact(fun, n):
return 1 if n==0 else fun(fun,n-1)*n
print(fact(fact,5))
其实很简单, 就是把 fact 这个函数本身传参进去, 这是第三步的基础
步骤3
我们先把 fact 写成一个 lambda
fact = lambda fun,n : 1 if n==0 else fun(fun,n-1)*n
然后把fact(fact,5)
里面的 fact 变量直接换成上面这个 ldmbda 就好了, 如下
fact = lambda fun,n : 1 if n==0 else fun(fun,n-1)*n
print((lambda fun,n : 1 if n==0 else fun(fun,n-1)*n)((lambda fun,n : 1 if n==0 else fun(fun,n-1)*n),5))
但这样有两个缺点
- 大段的代码重复
- 我们本来只是传参一个数字, 但现在还要传参一个匿名函数
这就不太体面了, 需要继续修改下. 这也就是步骤3的意义所在.
我们再定义一个函数 r 如下
def r(f,n):
return f(f,n)
r 函数有个优点: 短. 我们只要把 fact 代入这个短的函数中, 就可以去掉大段的重复代码了. 完成代码如下:
fact = lambda fun,n : 1 if n==0 else fun(fun,n-1)*n
r = lambda f,n: f(f,n)
print(r(fact,5))
把变量替换掉, 就变成一行代码了
print((lambda f,n: f(f,n))((lambda fun,n : 1 if n==0 else fun(fun,n-1)*n),5))
步骤4
但是缺点2还是没有解决掉, 步骤4就是解决这个问题的.
我们引入一个高阶函数 h, 这个函数返回另外一个函数 inner , inner 是一个参数为 int 的函数, 如下
其实就是把上面的代码复制到了 h() 里面
def h():
def inner(n):
fact = lambda fun,n : 1 if n==0 else fun(fun,n-1)*n
r = lambda f,n: f(f,n)
return r(fact,n)
return inner
print(h()(5))
把变量替换一下
def h():
return lambda n:(lambda f,n: f(f,n))((lambda fun,n : 1 if n==0 else fun(fun,n-1)*n),n)
print(h()(5))
把 h 也替换掉
print((lambda:lambda n:(lambda f,n: f(f,n))((lambda fun,n : 1 if n==0 else fun(fun,n-1)*n),n))()(5))
或者也可以写成
print((lambda n:lambda:(lambda f,n: f(f,n))((lambda fun,n : 1 if n==0 else fun(fun,n-1)*n),n))(5)())
把 fun 全部换成 f , 能短一点是一点
print((lambda:lambda n:(lambda f,n:f(f,n))((lambda f,n:1 if n==0 else f(f,n-1)*n),n))()(5))
补充 2020-01-16T12:24:07+0800
觉得第四步可以把最外层的 h() 扒掉.
def h():
return lambda n:(lambda f,n: f(f,n))((lambda fun,n : 1 if n==0 else fun(fun,n-1)*n),n)
print(h()(5))
像上面这段代码, 其实没有必要先返回一个函数然后再调用这个函数. 可以直接调用, 如下
(lambda n:(lambda f,n:f(f,n))((lambda f,n:1 if n==0 else f(f,n-1)*n),n))(5)