我们有函数:
def f1():
print(‘This is a function.’)
有一天我想添加需求,想在函数内部打印时间:
def f1():
print(time.time()) # 打印unix时间戳
print(‘This is a function.’)
f1()
后来我不只想在该函数实现打印时间的功能,我还想在更多函数中实现它。
我们定义函数:
def print_current_time(func): # 接收一个函数作为参数
print(time.time())
func()
print_current_time(f1)
print_current_time(f2)
这样就实现了我们的需求。但这样做不够好,打印时间这个新增加的需求并非属于新增加的函数,而是属于原函数(f1、f2)本身。这样的做法就如同下述代码:
print(time.time())
f1()
print(time.time())
f2
如何体现这种绑定,表示该扩展功能是属于原函数的呢?我们尝试使用装饰器:
def decorator(func): # 外部函数
def wrapper(): # 单词本身指被封装的意思
print(time.time())
func()
return wrapper
def f1():
print(‘This is a function.’)
这个就是装饰器本器了。但跟我们之前定义的有什么不同呢?区别在于装饰器把current_time函数封装到了内部,同时我们无需定义一个新的print_current_time函数。
如何使用?
f = decorator(f1) # 获取到wrapper
f()
真正的业务逻辑被包装在了在wrapper里。但我认为真正体现装饰器的优势是python给装饰器提供的一个语法糖,也就是“@”符号:
@decorator
def f1():
print(‘This is a function’)
f1()
它可以在不改变原函数的方法的基础上实现新增的方法,体现了AOP的思想。
现在我们考虑添加参数的情况。假设f1里有1个参数:
@decorator
def f1(func_name):
print(‘This is a function’)
f1(‘test_func’)
这样会报错,因为wrapper内部是没有参数的。正确的做法应该是:
def decorator(func):
def wrapper(func_name):
print(time.time())
func()
return wrapper
但如果原函数有N个参数呢?使用想变参数*args:
def decorator(func):
def wrapper(*args):
print(time.time())
func(*args)
return wrapper
这样不管原函数有多少个参数,都可以支持。我们继续优化我们的装饰器,还有一种情况,假设有函数f3:
# @decorator 不使用装饰器
def f1(func_name1,func_name2, **kw):
print(‘This is a function named’ + func_name1)
print(‘This is a function named’ + func_name2)
print(kw)
f3(‘test func1’, ‘test func2’, a=1, b=2, c=’123’)
>>{‘a’:1, ‘b’:2, ‘c’:3} # kw输出结果
如果要使用装饰器需要这样写:
def decorator(func):
def wrapper(*args, **kw):
print(time.time())
func(*args, **kw)
return wrapper