装饰器_二(自定义装饰器)

什么是装饰器:

装饰器利用了函数也可以作为参数传递和闭包的特性,可以让我们的函数在执行之前或者执行之后方便的添加一些代码。这样就可以做很多的事情了,比如@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')

wraps装饰器

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装饰器,避免这种情况发生。

你可能感兴趣的:(python)