重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
在理解装饰器的概念前,我们首先看一下function和inner function在python中的含义。
成都创新互联是专业的澜沧网站建设公司,澜沧接单;提供成都网站设计、做网站,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行澜沧网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
function:在python中,function就像其他对象一样,可以当做参数或返回值。
inner function:一个函数A(inner function)定义在另一个函数B中。函数A就叫做inner function。
# 函数用做参数
def hello():
print("hello")
def welcome():
print("Welcome")
def say_something(func):
func()
# 函数add在函数cal中定义,并且用做返回值
def cal():
def add(a,b):
print(a+b)
return add
注意:此时add不能直接被外界调用,因此此时内部函数还未定义。但可以通过cal将add的引用返回,用于在将来调用。
decorator:封装了一个函数,并且改变了其行为
装饰器本质上,是将要被装饰的函数作为参数,并且返回一个包裹其的、内部定义的函数。如下所示:my_decorator返回了wrapper的引用,用于将在将来执行。
def hello():
print("hello")
def my_decorator(func):
def wrapper():
print("before func work")
func()
print("after func work")
return wrapper
hello_d = my_decorator(hello)
hello_d()
"""
before func work
hello
after func work
"""
hello_d便是经过my_decorator装饰的函数。我们明显发现,过程有些复杂,为了简化步骤,python提供了@decorator
的语法糖。
下面,我们使用@decorator
达到同样的目的。
@my_decorator
def hello():
print("hello")
def my_decorator(func):
def wrapper():
print("before func work")
func()
print("after func work")
return wrapper
hello()#与hello = my_decorator(hello)作用相同
"""
before func work
hello
after func work
"""
在装饰器中,wrapper的命名可自定义。
观察上面的例子,由于hello被my_decoratorx装饰过,此时在python shell查看hello的__name__,发现
这对我们来说,不是有用的信息,为了“正确”显示,使用@functools.wrap(func)
import functools
@my_decorator
def hello():
print("hello")
def my_decorator(func):
@functools.wrap(func)
def wrapper():
print("before func work")
func()
print("after func work")
return wrapper
然后便可以达到和装饰器装饰前同样的效果:
# do twice
def do_twice(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
func(*args,**kwargs)
func(*args,**kwargs)
return wrapper
# timer
def timer(func):
@functools.wraps(func)
def wrapper_timer(*args, **kwargs):
start_time = time.perf_counter()
value = func(*args, **kwargs)
end_time = time.perf_counter()
run_time = end_time - start_time
print(f"Finished {func.__name__} in {run_time:.4f} seconds")
return value
return wrapper_timer
@timer
def waste_time(num):
for _ in range(num):
sum([i **2 for i in range()])
waste_time(1000)
# flask check user login
def login_required(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
if g.user is None:
return redirect(url_for('login',next=request.url))
return func(*args, **kwargs)
return wrapper
@app.route('/secret')
@login_required
def secret():
...
decorator用于“包裹”一个函数,改变其行为。
在装饰器的wrapper中并不一定要执行该函数,也可以保留函数的引用,用于插件的注册。
realpython