1.先回顾函数的几个概念
1.1 函数可以赋予变量
def func(message):
print("Got a message: {}".format(message))
send_message = func
send_message("helloworld")
# 输出
Got a message: helloworld
在上面的例子中,函数func()
赋给了变量send_message
,这样调用send_message
就相当于调用了函数func()
。
1.2 函数可以当作参数
def get_message(message):
return 'Got a message: ' + message
def root_call(func, message):
print(func(message))
root_call(get_message, 'hello world')
# 输出
Got a message: hello world
在这个例子中,函数get_message()
就作为函数root_call()
的参数。
1.3 函数可以嵌套
def func(message):
def get_message(message):
print('Got a message: {}'.format(message))
return get_message(message)
func('hello world')
# 输出
Got a message: hello world
这里在函数func()
中嵌套了另一个函数get_message()
,调用后作为func()
的返回值返回。
1.4 函数的返回值可以是函数对象(闭包)
def func_closure():
def get_message(message):
print('Got a message: {}'.format(message))
return get_message
send_message = func_closure()
send_message('hello world')
# 输出
Got a message: hello world
这个例子中,函数func_closure()
的返回值是函数对象get_message()本身,之后将其赋给了变量send_message,再调用send_message。
2. 简单的装饰器
def my_decorator(func):
def wrapper():
print("wrapper of decorator")
func()
return wrapper
def greet():
print('hello world')
greet = my_decorator(greet)
greet()
# 输出
wrapper of decorator
hello world
上述例子中,变量greet指向内部函数wrapper()
,内部函数wrapper()
调用原函数greet()
。最后调用greet()
时,先打印“wrapper of decorator”,然后再打印“hello world”。
这里的函数my_decorator()
就是一个装饰器,它把真正需要执行的函数greet()包裹在其中,并且改变了它的
行为,但是原函数greet()不变。
还可以使用更简洁的表示:
def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper
@my_decorator
def greet():
print('hello world')
greet()
上面例子中的@my_decorator
就相当于greet = my_decorator(greet)
,只不过更加简洁。
3. 带有参数的装饰器
建议直接设置“*args, **kwargs
”,这样就能传入多个参数
def my_decorator(func):
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
4. 保留原函数的元信息
函数被装饰后,函数的元信息就会改变,例如上面的函数greet()
被装饰以后,就变成了wrapper()
。为了解决这个问题,我们可以使用内置的装饰器@functools.wrap
来保留函数的元信息。其作用就是将元信息拷贝到对应的装饰器函数里。
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
@my_decorator
def greet(message):
print(message)
greet.__name__
# 输出
'greet'
5. 类装饰器
前面主要讲函数作为装饰器的用法,而类也可以作为装饰器。类装饰器主要依赖函数__call__()
。
class Count:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print('num of calls is: {}'.format(self.num_calls))
return self.func(*args, **kwargs)
@Count
def example():
print('hello world')
example()
# 输出
num of calls is: 1
hello world
example()
# 输出
num of calls is: 2
hello world
6. 装饰器的嵌套
例如:
@decorator1
@decorator2
@decorator3
def func():
...
上面的语句等同于:
decorator1(decorator2(decorator3(func)))
具体示例:
import functools
def my_decorator1(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute decorator1')
func(*args, **kwargs)
return wrapper
def my_decorator2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute decorator2')
func(*args, **kwargs)
return wrapper
@my_decorator1
@my_decorator2
def greet(message):
print(message)
greet('hello world')
# 输出
execute decorator1
execute decorator2
hello world
网友评论