一、装饰器python
不修改被装饰函数的定义,可是能够在代码运行期间动态增长功能的方式,称之为“装饰器“,
本质上,装饰器decorator就是一个返回函数的高阶函数设计模式
#!/usr/bin/env python #-*- coding:utf-8 -*- import math# 导入数学公式模块 from collections import Iterable# 判断是否为可迭代对象 import os# 导入os模块 import functools# 导入functools.wraps # Python将一切视为object的子类,即一切都是对象,固然函数也是一个对象,能够像变量同样被传递和指向 def foo(): print "I`m foo" f = foo f() # 函数对象有一个__name__的属性,能够获得函数的名字 print foo.__name__ print f.__name__ # ★不修改被装饰函数的定义,可是能够在代码运行期间动态增长功能的方式,称之为“装饰器“, # 例子:在函数调用先后自动打印日志 def logging1(func):# 装饰器函数logging1 def wrapper(*args, **kw):# 可变参数和关键字参数 print '%s is running...' % func.__name__ return func(*args, **kw) return wrapper # logging1是一个装饰器,它能接收一个函数作参数,并返回一个函数 @logging1 def foo(): print "I`m foo" # @符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操做 foo()# 调用foo()函数 # @logging1放到foo()函数的定义处,调用被装饰函数foo,不只会执行被装饰函数foo,还会执行logging1装饰器 # @logging1至关于执行了foo = logging1(foo)语句 # 分析:因为logging1() 是一个decorator,返回一个函数,原来的foo()函数仍然存在,只是如今同名的foo变量指向了新的函数,即在logging1()函数中返回的wrapper()函数;因而调用foo()将执行新wrapper()函数 # wrapper()函数的参数定义是(*args, **kw),所以,wrapper() 函数能够接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数foo() # ★有参数的装饰器,须要编写一个返回decorator的高阶函数 # 装饰器 def logging2(info): def decorator(func): def wrapper(*args, **kw): print '%s,%s is running...' % (info, func.__name__) return func(*args, **kw) return wrapper return decorator # 用法 @logging2('Waiting') def foo(): print "I`m foo" # 调用foo()函数 foo() # 这种三层嵌套结构的装饰器,执行过程是foo = logging2('Waiting')(foo) # 分析:首先执行logging2('Waiting'),返回的是decorator函数,再调用返回的decorator函数,参数是now函数,最终返回值是wrapper函数
运行效果:
二、内置的functools.wraps装饰器app
设计模式之装饰模式decorator函数
使用Python内置的functools.wraps,在实现以前加上functools的wraps,它能保留原有函数的名称和docstring
Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator能够用函数实现,也能够用类实现。设计
# ★函数也是对象,它有__name__ 等属性,但上面两个例子通过decorator装饰以后的函数,它们的__name__ 已经从原来的'now' 变成了'wrapper' print u'装饰后函数的名字:',foo.__name__ # 由于返回的那个函数是wrapper() ,因此,结果就是'wapper',如今须要把原始函数的__name__等属性复制到wrapper() 函数中,不然,有些依赖函数签名的代码执行就会出错。 # 可使用wrapper.__name__ = func.__name__ def logging3(info): def decorator(func): def wrapper(*args, **kw): wrapper.__name__ = func.__name__ print '%s,%s is running...' % (info, func.__name__) return func(*args, **kw) return wrapper return decorator @logging3('Waiting') def foo(): print "I`m foo" foo() print u'装饰后函数的名字:',foo.__name__ # 无参装饰器使用functools.wraps def logging4(func):# 装饰器函数logging4 @functools.wraps(func)# 使用functools.wraps保留原来函数的信息 def wrapper(*args, **kw):# 可变参数和关键字参数 print '%s is running...' % func.__name__ return func(*args, **kw) return wrapper @logging4 def foo(): print "I`m foo" foo() print u'无参装饰器使用functools.wraps:',foo.__name__ # 有参装饰器使用functools.wraps def logging5(info): def decorator(func): @functools.wraps(func)# 使用functools.wraps保留原来函数的信息 def wrapper(*args, **kw): print '%s,%s is running...' % (info, func.__name__) return func(*args, **kw) return wrapper return decorator @logging5('Waiting') def foo(): print "I`m foo" foo() print u'有参装饰器使用functools.wraps:',foo.__name__ # ★编写一个decorator,能在函数调用的先后打印出'begin call' 和'end call' 的日志 def logging6(info): def decorator(func): @functools.wraps(func)# 使用functools.wraps保留原来函数的信息 def wrapper(*args, **kw): print '%s...,begin call %s()' % (info, func.__name__)# 调用前 result = func(*args, **kw)# 由于不能直接返回,因此须要暂存结果 print 'end call %s()' % (func.__name__)# 调用后 return result return wrapper return decorator # 组建装饰器 @logging6('Waiting') def foo(): print "I`m foo" foo() # ★写出一个@log的decorator。使它既支持:@log,又支持:@log('execute') def logging7(info): if isinstance(info,str): # 有参装饰器 def decorator(func): @functools.wraps(func) def wrapper(*args,**kw): print u'%s,有参%s is running...' %(info,func.__name__) func(*args,**kw) print u'有参%s is enddning...' %(func.__name__) return wrapper return decorator else: # 无参装饰器 @functools.wraps(info) # 此时info就是被装饰函数 def wrapper(*args,**kw): print u'请等待,无参%s is running...' %(info.__name__) info(*args,**kw) print u'无参%s is enddning...' %(info.__name__) return wrapper # 组建无参装饰器 @logging7 def foo(): print "I`m foo" foo() # 组建有参装饰器 @logging7('Waiting') def foo(): print "I`m foo" foo()
运行效果:日志
三、functools.partial偏函数code
偏函数:经过设定参数的默认值,下降函数调用的难度对象
functools模块除了wraps装饰器外,还有好多其余函数,例如偏函数functools.partial,区别于数学意义上的偏函数
utf-8
#!/usr/bin/env python #-*- coding:utf-8 -*- import math# 导入数学公式模块 from collections import Iterable# 判断是否为可迭代对象 import os# 导入os模块 import functools# 导入functools.wraps # int():默认参数base=10 print u'默认十进制', int('12') # 必选参数 # 结果:123456 print u'八进制数:', int ('12',base = 8)# 默认参数 # 结果:10 # base表示该字符串转换为整数时,采用的进制。而输出的是十进制 # 而若是转换大量的八进制字符串,每次都传入int (x,base = 8)是比较麻烦的,为此咱们能够定义int8(x,base = 8) def int8(x,base = 8): return int(x,base) print u'八进制数:', int8('12') # 也可使用functools.partial,这样就不用从新def定义新函数int8()了 int8 = functools.partial(int ,base = 8) print u'使用functools.partial的八进制数:',int8('15') # int8函数把参数从新设定默认值为8 ,但也能够在函数调用时传入其余值。例如:int8('15',base = 16) # 建立偏函数时,实际上能够接收函数对象、*args 和**kw 这3个参数 # int8 = functools.partial(int ,base = 8)其实是固定了关键字参数的值为8,等效于kw = {'base' : 8} int('15', **kw) # max_ex = functools.partial(max ,10,12)# 会把10,12做为可变参数自动添加到右边,max_ex(1,2,3)等效于max(1,2,3,10,12)
运行效果:字符串
★当函数的参数个数太多,使用functools.partial 能够建立一个新的函数,这个新函数能够把原函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,从而在调用时更简单