什么是好的抽象?
比如这样一个函数:
def accumulate(combiner, base, n, term):
total, k=base, 1
while k<=n:
total,k = combiner(total, term(k)), k+1
return total
利用这个函数能够构建出不同的符合这个抽象的函数。
比如 将0-x间的不同特征的数相加:
term函数可以是平方,立方
def summation_using_accumulate(n, term):
return accumulate(add, 0, n, term)
相乘:
def product_using_accumulate(n, term):
return accumulate(mul, 1, n, term)
将0-x间的数过滤出来相加可以这样子做:
def filtered_accumulate(combiner, base, pred, n,term):
def combiner_if(x,y):
if pred(y):
return combiner(x,y)
else:
return x
return accumulate(combiner_if, base, n, term)
利用一个高阶函数,pred是过滤的规则
比如只要偶数
odd = lambda x: x%2==1
filtered_accumulate(add, 0, odd, x, term)
再比如对一个函数多次调用
repeated(square, 2)(5) = square(square(5))
利用高阶函数能够很简单实现。
def repeated(f, n):
def inner(x):
nonlocal n
if n == 0:
return x
result = x
while n > 0:
result = f(result)
n -= 1
return result
return inner
但是仔细想想,似乎能够用上面的那个函数来写 可以这样做:
定义一个高阶函数
def compose(f, g):
def h(x):
return f(g(x))
return h
def repeated(f, n):
return accumulate(compose, lambda x:x, n,lambda k:f)
发现 要进行0-n次term计算,用compose来组合起来 都可以用accumuldate这个抽象
比如上面这个例子 对x进行term计算,然后组合.
lambda 表达式,注意它是运行时绑定的。
>>> a=3
>>> b=2
>>> c = lambda a,b:a+b
>>> b-=a
>>> c(a,b)
2
递归:
以常见的斐波那契数列来说
树形递归,复杂度最高,有很多的重复计算。
从f(1)=1开始的。
def fib(n):
if n<2:
return n
return fib(n-1)+fib(n-2)
我们可以这样子写,利用数来保存中间变量,不用重复计算。
def fib2(a,b,n):
if n > 0:
return fib2(b,a+b,n-1)
return a
装饰器:
@decorator
def func
相当于decorator(func)
能够用装饰器做很多事情。比如:
定义一个memo缓存函数,来优化上面的fib
def memo(f):
cache = {}
def helper(*args):
if args not in cache:
cache[args]=f(args)
return cache[args]
return helper
利用了一个缓存来保存变量。
总结 要多思考建立好的函数抽象。
函数编码原则:
- 函数名 称应 该小写 , 以下划 线分隔。 提倡描述性的名 称。
- 函数名 称通常反映解释器 向参数应 用 的操作( 例如 print 、 add 、 square ) , 或者结
果( 例 如 max 、 abs 、 sum ) 。 - 参数名 称应 小写 , 以下划 线分隔。 提倡单个词的名 称。
- 参数名 称应 该反映参数在函数中 的作用 , 并不仅仅是满足的值的类型 。
- 当 作用 非常明 确时, 单个字母的参数名 称可以接受, 但是永远不要使用 l ( 小写 的 L )
和 O ( 大写 的 o ) , 或者 I ( 大写 的 i ) 来避免和数字混淆。
函数设计原则
一个函数只完成一个功能,遵循dry原则。
写函数帮助文档,利用doctest进行测试。
调试的一些原则:
逐步测试,隔离错误,追踪到最小的代码片。检查假设。