建立函数抽象

什么是好的抽象?

比如这样一个函数:

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
利用了一个缓存来保存变量。

总结 要多思考建立好的函数抽象。

函数编码原则:

  1. 函数名 称应 该小写 , 以下划 线分隔。 提倡描述性的名 称。
  2. 函数名 称通常反映解释器 向参数应 用 的操作( 例如 print 、 add 、 square ) , 或者结
    果( 例 如 max 、 abs 、 sum ) 。
  3. 参数名 称应 小写 , 以下划 线分隔。 提倡单个词的名 称。
  4. 参数名 称应 该反映参数在函数中 的作用 , 并不仅仅是满足的值的类型 。
  5. 当 作用 非常明 确时, 单个字母的参数名 称可以接受, 但是永远不要使用 l ( 小写 的 L )
    和 O ( 大写 的 o ) , 或者 I ( 大写 的 i ) 来避免和数字混淆。

函数设计原则

一个函数只完成一个功能,遵循dry原则。
写函数帮助文档,利用doctest进行测试。
调试的一些原则:
逐步测试,隔离错误,追踪到最小的代码片。检查假设。

来自http://www.97up.cn/post/83

你可能感兴趣的:(建立函数抽象)