装饰器利用了函数也可以作为参数传递和闭包的特性,可以让我们的函数在执行之前或者执行之后方便的添加一些代码。这样就可以做很多的事情了,比如@classmethod装饰器可以将一个普通的方法置为类方法,@staticmethod装饰器可以将一个普通的方法置为静态方法等。所以明白了装饰器的原理后,我们就可以自定义装饰器,从而实现我们自己的需求。
理解:
拿网站开发的例子来说。网站开发中,经常会碰到一些页面是需要登陆后才能访问的。那么如果每次都在访问视图函数中判断,很麻烦,而且代码很难维护。
user = {
'is_login': False
}
def edit_user():
if user['is_login'] == True:
print('用户名修改成功')
else:
print('跳转到用户登陆界面')
def add_article():
if user['is_login'] == True:
print('文章添加成功')
else:
print('跳转到用户登陆界面')
edit_user()
add_article()
以上现在只是两个函数,如果网站越来越大,需要判断的地方也越来越大,那么这种判断将显得非常低效并且难于维护。
使用装饰器来实现判断网站登陆:
def check_login(func):
# wrapper这个函数名字可以自定义,一般习惯性用这个名字
def wrapper():
if user['is_login'] == True:
func()
else:
print('跳转到用户登陆界面')
return wrapper
@check_login
def edit_user():
print('用户名修改成功')
def add_article():
if user['is_login'] == True:
print('文章添加成功')
else:
print('跳转到用户登陆界面')
# 执行 edit_user() == check_login(edit_user)()
# edit_user = wrapper
edit_user()
上述我们实现的对登陆的装饰,如果登陆是需要传递用户名,来指出是谁登陆成功了,在添加文章的时候需要传递文章的标题和内容,这时我们就需要传递参数
# -*- coding: UTF-8 -*-
user = {
'is_login': True
}
def check_login(func):
# wrapper这个函数名字可以自定义,一般习惯性用这个名字
def wrapper(*args, **kwargs):
print(kwargs)
if user['is_login'] == True:
func(*args, **kwargs)
else:
print('跳转到用户登陆界面')
return wrapper
@check_login
def edit_user(username):
print('用户名%s 修改成功' % username)
@check_login
def add_article(title=None, content=None):
print('%s %s 添加成功' % (title, content))
# 执行 edit_user() == check_login(edit_user)()
# edit_user = wrapper
edit_user('lyc')
add_article(title='测试', content='文章内容')
应用场景:当我们需要区分是前台还是后台调用修改用户的接口,来区分返回跳转到前台登陆页面还是后台登陆页面时
user = {'is_login': True}
def login_required(site='front'):
def outer_wrapper(func):
def inner_wrapper(*args, **kwargs):
if user['is_login'] == True:
func(*args, **kwargs)
else:
if site == 'front':
print('跳转到前台登陆页面')
else:
print('跳转到后台登陆页面')
return inner_wrapper
return outer_wrapper
@login_required('front')
def edit_user(username):
print('用户名%s 修改成功' % username)
edit_user('lyc')
from functools import wraps
def greet(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('%s start run' % func.__name__)
func(*args, **kwargs)
print('%s run end' % func.__name__)
return wrapper
@greet
def add(x, y):
print('%d + %d = %d' %(x, y, x+y))
add(1, 19)
print(add.__name__)
如果我们不用wraps装饰器,那么print(add.name) 打印结果为 wrapper。 因此,我们在自定义装饰器的时候,要注意在实际执行函数前加上wraps装饰器,避免这种情况发生。