修饰符基础——闭包
什么是闭包呢?标准的概念大家可以看wikipedia上的解释点击打开链接 举个例子:
- def do_add(base):
- def add(increase):
- return base + increase
- return add
do_add函数里嵌套了一个内层函数add,这个内层函数就是一个闭包,其实可以也不用管这个“闭包”的概念,先来看下这种模式解决些什么问题.
调 用do_add函数:a = do_add(23),由于内层的函数add里的逻辑用到了do_add函数的入参,而这时这个入参base绑定了值23,由于do_add函数返回的是 函数add,所以这时的a其实就是内部的add绑定了23的函数add;同理可知,b = do_add(44),这里的b就是内部add绑定了44的函数add,a和b这两个add函数是不相同的,因为内部add绑定的值不同,只是两个函数的 模板相同罢了,这时我们执行a(100)得到结果是123,b(100)得到结果是144。这样做有什么用呢?其实可以这样看:我们可以把a = do_add(23)和b = do_add(44)看成是配置过程,23和44是配置信息,a(100)和b(100)根据不同的配置获得不同的结果,这样我们就可以解决开发中“根据 配置信息不同获得不同结果”的问题
而修饰符实际上就是闭包一种形式,只是配置过程参数是所修饰的一个函数,并且用@符号代替了a=do_add(23)这样的配置方式,下面看一下修饰符的用法
修饰符用法
修饰符无参数,原函数无参数
- import time
- def timeit(func):
- def wrapper():
- start = time.clock()
- func()
- end =time.clock()
- print ‘used:‘, end - start
- return wrapper
- @timeit
- def foo():
- print ‘in foo()‘
- foo()
如上代码:对所修饰函数运行时间的进行统计,最后修饰过的 foo() 等价于 foo=timeit(foo) 而timeit返回wrapper,归根到底真正执行的是wrapper
在实际应用中,函数很少没有参数,所以我们看看foo有参数的情况下,修饰符怎么用
修饰符无参数,原函数有参数
- import time
- def timeit(func):
- def wrapper(args):
- start = time.clock()
- func(args)
- end =time.clock()
- print ‘used:‘, end - start
- return wrapper
- @timeit
- def foo(arg):
- print ‘in foo(),arg is‘ + arg
- foo("aaaaa")
上述过程可以简化如下:
[decorated] foo(‘aaaaa’) => timeit(foo)(‘aaaaa’) => wrapper(‘aaaaa’) => [real] foo(‘aaaaa’)
如果修饰符函数也有参数,又怎么用呢?
修饰符有参数,原函数有参数
- import time
- def timeit(s):
- def wrapper1(func)
- def wrapper2(args):
- print "the decorator‘s arg is"+s
- start = time.clock()
- func(args)
- end =time.clock()
- print ‘used:‘, end - start
- return wrapper2
- return wrapper1
- @timeit(s="hello")
- def foo(arg):
- print ‘in foo(),arg is‘ + arg
- foo("aaaaa")
- 同理,就是多加了一层闭包。
应用多个修饰符
这个记住一个结论就好了,就是修饰符从离原函数最近的开始包裹,最外层的修饰符最后包裹
应用举例——Fibonacci数列
- def memoize(f):
- cache = {}
- def helper(x):
- if x not in cache:
- cache[x] = f(x)
- return cache[x]
- return helper
- @memoize()
- def fib(n):
- if n in (0, 1):
- return n
- else:
- return fib(n - 1) + fib(n - 2)