装饰器Decorator,是在代码运行期间动态增加功能的方式,其实体现了一种设计模式即强调的是开放封闭原则,现对其定义不做多的说明,主要为其敲黑板记重点。
decorator就是一个返回函数的高阶函数。现模拟一个打招呼场景。
def SayHello(func):
def how(*args, **kw):
print('How about u %s' % func.__name__)
return func(*args, **kw)
return how
@SayHello
def Jack():
print('I am fine')
Jack()
输出结果为:
How about u Jack
I am fine
我们在一开始定义了SayHello这个装饰器,参数接收函数并返回函数。根据语法知识,将@SayHello置于函数Jack()上方,且只能放在被装饰的函数的上方最近处,不能空行。
当程序执行到函数Jack()时,则会开始执行@SayHello内的函数。
实际上是相当于执行了Jack= SayHello(Jack),此时变量名Jack则指向了内部函数指向的函数体内存地址,而不再指向它原来的函数体的内存地址。
内部函数how的参数定义是(*args, **kw),可以接受任意参数的调用。于是先打印出了How about u+Jack函数名,接着再调用回函数Jack()。
此时再次打印函数名Jack._name_时,会打印的不是原来的Jack()而是how(),具体原因可看上述,为了避免依赖于代码签名的程序报错,应在内部函数how()上面添加
@functools.wraps(func)
接下来拓展下如何编写能在函数调用的前后都有打印语句的写法
def SayHello(func):
def how(*args, **kw):
print('How about u? %s' % func.__name__)
result = func(*args, **kw)
print('I am fine too!')
return result
return how
@SayHello
def Jack():
print('I am fine, and u?')
Jack()
打印结果为
How about u? Jack
I am fine, and u?
I am fine too!
要注意的是,result = func(*args, **kw)不能写为result = func,因为这表示将func函数的函数名当做参数传递给result,实际上是一个None值。
若原始参数需要参数呢,那我们就可以使用万能参数*args和**kw,比如从原始函数传递一个GoodMorning问候
def SayHello(func):
def how(*args, **kw):
print('How about u? %s' % func.__name__)
result = func(*args,**kw)
print('I am fine too!')
return result
return how
@SayHello
def Jack(today):
print("%s, I am fine, and u?"%today)
Jack("GoodMorning ")
输出结果为
How about u? Jack
GoodMorning , I am fine, and u?
I am fine too!
若decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,如传入一个时间
def funlog(time):
def SayHello(func):
def how(*args, **kw):
print('%s' %time)
return func(*args,**kw)
return how
return SayHello
@funlog('2016-11-8')
def Jack():
print("I am fine")
Jack()
输出结果为
2016-11-8
I am fine
一个原始函数也可以被多个函数修饰,但要注意@语法顺序
def SayHello(func):
def One(*args, **kw):
print('OneBegin' )
result1 = func(*args,**kw)
print('OneOver' )
return result1
return One
def SayHi(func):
def Two(*args, **kw):
print('TwoBegin' )
result2 = func(*args,**kw)
print('TwoOver' )
return result2
return Two
@SayHello
@SayHi
def Jack():
print("Jack")
Jack()
输出结果如下
OneBegin
TwoBegin
Jack
TwoOver
OneOver