Python168的学习笔记8
#coding:utf8 #斐波那契数列,第三项起,每一项都等于前两项之和 def memo(func): cache = {}#闭包 def wrap(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrap @memo def fibonacci(n): if n<=1: return 1 return fibonacci(n-1)+fibonacci(n-2) #上楼梯算法,总过n个台阶,一次只能迈a-b个台阶,不能后退,问有几种走法 @memo def climb(n,steps): count = 0 if n==0: count = 1 elif n>0: for step in steps: count += climb(n-step,steps) return count
装饰器的简单应用还是明白的,但是要理解这两个递归算法。
关于函数的元数据,如:f.__name__,指的是def时指定的名字;f.__doc__,指的是函数文档字符串;f.__moudle__,指的是函数所属模块;f.__default__,指的是函数默认值;f.__dict__,指的是属性字典;f.__closure__,指的是函数的闭包。。。这些元数据都是func的属性。
使用装饰器可能会改变func的元数据。
#coding:utf8 from functools import update_wrapper,wraps,WRAPPER_ASSIGNMENTS,WRAPPER_UPDATES def mydecorator(func): @wraps(func)#第一种 def wrapper(*args,**kw): '''wrapper function''' print 'In wrapper' func(*args,**kw) #wrapper.__name__ = func.__name__ 第二种 #update_wrapper(wrapper,func,('__name__','__doc__'),('__dict__',))#第四个参数是将func的属性更新到wrap #第三种:update_wrapper后两个的默认参数分别是('__module__', '__name__', '__doc__');('__dict__',) return wrapper @mydecorator def example(): '''example function''' print 'In example'
其实就是对处理后的func的属性进行重新赋回原来的值。
定义带参数的装饰器,就是用去判断参数的类型,因为要用过python3的库,所以先略过。
修改装饰器的属性。这样的好处是能够在运行中动态修改,而不是每次都要去装饰器处修改。
给包裹函数增加一个函数,作为包裹函数的属性,使其可以修改闭包中的自由变量。
1 import time 2 from functools import wraps 3 import logging 4 5 def warn(timeout): 6 timeout = [timeout]#将参数设为只有一个数的list 7 def decorator(func): 8 @wraps(func) 9 def wrapper(*args,**kw): 10 start = time.time() 11 res = func(*args,**kw) 12 used = time.time()-start 13 if used > timeout[0]: 14 msg = '%s : %s >%s' %(func.__name__,used,timeout[0]) 15 logging.warn(msg) 16 return res 17 def setTimeout(k):#注意这里 18 timeout[0] = k 19 wrapper.setTimeout = setTimeout 20 return wrapper 21 return decorator 22 23 from random import randint 24 @warn(0.5) 25 def test(): 26 print 'In test' 27 while randint(0,1): 28 print 'I am sleep' 29 time.sleep(1) 30 31 for _ in range(10): 32 test() 33 34 test.setTimeout(1) 35 for _ in range(10): 36 test()
使用类来定制装饰器。
1 #coding:utf8 2 import logging 3 from time import localtime,time,strftime,sleep 4 5 class CallingInfo(object): 6 def __init__(self,name): 7 log = logging.getLogger(name) 8 log.setLevel(logging.INFO)#设置等级 9 fh = logging.FileHandler(name+'.log')#设置文件处理方法 10 log.addHandler(fh)#绑定方法到log上 11 log.info('Start'.center(50,'-'))#添加log文本的头部 12 self.log= log#绑定到类的属性上 13 self.formatter = '%(func)s ->[%(time)s - %(used)s -%(ncalls)s]'#定义了输出模板 14 15 def info(self,func):#这个就是平常的装饰器 16 def wrapper(*args,**kw): 17 wrapper.ncalls +=1 18 lt = localtime()#返回当地时间 19 start = time() 20 res = func(*args,**kw) 21 used = time() - start 22 23 info = {}#建立info的字典 24 info['func'] = func.__name__ 25 info['time'] = strftime('%x %X',lt) 26 info['used'] = used 27 info['ncalls'] = wrapper.ncalls 28 29 msg = self.formatter % info#将字典映射到输入模板上 30 self.log.info(msg)#输出字符串 31 return res 32 wrapper.ncalls = 0#这个语句需要在这个位置的解释有待完善 33 return wrapper 34 35 def setFromatter(self,formatter): 36 self.formatter = formatter 37 38 def turnOn(self): 39 self.log.setLevel(logging.INFO) 40 41 def turnOff(self): 42 self.log.setLevel(logging.WARN)#级别提高就不在那里输出了 43 44 cinfo1 = CallingInfo('mylog1') 45 cinfo2 = CallingInfo('mylog2') 46 47 cinfo1.setFromatter('%(func)s ->[%(time)s -%(ncalls)s]') 48 cinfo2.turnOff()#这里可以看到是很方便地修改装饰器 49 50 @cinfo1.info 51 def f(): 52 print 'in f' 53 54 @cinfo1.info 55 def h(): 56 print 'in h' 57 58 @cinfo2.info 59 def g(): 60 print 'in g' 61 62 63 from random import choice 64 for _ in xrange(10): 65 choice([f,g,h])() 66 sleep(choice([0.5,1,1.5]))