Python_day07--装饰器-(多个装饰器的执行顺序、及应用)

一、多个装饰器的执行顺序

前面我们说到了装饰其的用法,以及他的作用;可是在工作中我们经常能看到装饰器可能不止使用一次,在同一个函数下我们有可能加上好几个装饰器,那他们的运行机制:

例:

def decorator_a(func):
    print('count 1')
    def inner_a(*args, **kwargs):
        print('count 2')
        return func(*args, **kwargs)
    return inner_a

def decorator_b(func):
    print('count 3')
    def inner_b(*args, **kwargs):
        print('count 4')
        return func(*args, **kwargs)
    return inner_b

# 当有多个装饰器时, 从下到上调用装饰器;
@decorator_b   #  f =  decorator_b(inner_a)   # f = inner_b
@decorator_a   # f = decorator_a(f)    # f = inner_a
def f(x):
    print('Get in f')
    return x * 2

f(1)   # inner_b(1)

我们看到了上面的结果,函数在调用装饰器时是自下向上的顺序进行的

多个装饰器我认为:函数调用是从下到上,但是装饰器最终要找到最后一层的函数;以上面的例子来说,当函数发现有装饰器时,系统中已经默认把装饰器放在内存中了,它先去找decorator_a,发现她并不是最底层函数,向下一个装饰器b读取,当把装饰器b陨星完时,发现这才是最底层的函数,那么它又安原来的路线逐级返回;说的并不是特别清楚,我用几个例字实践:

例如:我们可以多定义几个装饰器,从而寻找他的运行规律;

def decorator_a(func):
    print('函数a_1')
    def inner_a(*args, **kwargs):
        print('函数a_2')
        return func(*args, **kwargs)
    return inner_a

def decorator_b(func):
    print('函数b_1')
    def inner_b(*args, **kwargs):
        print('函数b_2')
        return func(*args, **kwargs)
    return inner_b

def decorator_c(func):
    print('函数c_1')
    def inner_a(*args, **kwargs):
        print('函数c_2')
        return func(*args, **kwargs)
    return inner_a

def decorator_d(func):
    print('函数d_1')
    def inner_a(*args, **kwargs):
        print('函数d_2')
        return func(*args, **kwargs)
    return inner_a

# 当有多个装饰器时, 从下到上调用装饰器;
@decorator_d
@decorator_c
@decorator_b   
@decorator_a   
def f(x):
    print('Get in f')
    return x * 2
f(1)   

这样的理解方式是不太好,没有从源码的底层上去理解;但是就目前而言我能够想的通,可能并不准确。如果正在看的你是个大佬那还请你多提一些建议,好让我有更深层次的理解

二、多个装饰器的应用

例:在实际的应用场景中,会采用多个装饰器先验证是否登陆成功,再验证权限是否足够;

import functools
import inspect

def is_admin(fun):  # fun=add_student
    @functools.wraps(fun)
    def wrapper(*args, **kwargs): # kwargs = {'name':'root'}
        # inspect.getcallargs返回一个字典, key值为:形参, value值为对应的实参;
        inspect_res = inspect.getcallargs(fun, *args, **kwargs)
        print("inspect的返回值: %s" %(inspect_res))

        if inspect_res.get('name') == 'root':
            temp = fun(*args, **kwargs)
            return temp
        else:
            print("Error:not root/admin user, no permisson add student")   # 抛出异常
    return wrapper



login_seesion = ['root', 'admin', 'redhat']

def is_login(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        if args[0] in login_seesion:
            temp = fun(*args, **kwargs)
            return temp
        else:
            print("Error: %s未登陆!" %(args[0]))
    return wrapper

@is_login
@is_admin  # is_admin()
def add_student(name):
    print("添加学生信息.....")
add_student('admin')

1、is_admin函数会帮你判断你所登陆的用户是否有权限

2、is_login函数判断你是否登陆了

我们先不运行程序,先来数理一遍;首先我们调用的is_admin函数,在运行完is_admin外层函数时发现还有一个装饰器函数,然后把参数传向is_login函数,把is_login函数外层函数运行结束后,系统发现并没有第三个装饰器,那么is_login里的warpper函数就是最底层函数,那么它就依次执行完is_login里的所有函数,再原路返回去寻找上一层函数直到函数运行结束;

三、带有参数装饰器练习_参数检测

上面我们说的都是无参装饰器,如果给装饰器戴上参数呢?

 2. 升级版(有参数的装饰器)
编写装饰器required_types, 条件如下:
    1). 当装饰器为@required_types(int,float)确保函数接收到的每一个参数都是int或者float类型;
    2). 当装饰器为@required_types(list)确保函数接收到的每一个参数都是list类型;
    3). 当装饰器为@required_types(str,int)确保函数接收到的每一个参数都是str或者int类型;
    4). 如果参数不满足条件, 打印 TypeError:参数必须为xxxx类型

def required_types(*types):
    def required(f):
        def wrapper(*args, **kwargs):  # args=(1,2)
            # 1. 判断每一个元素都是整形;
            for i in args:
                if not isinstance(i, types):
                    print("Error:参数必须为",types)
                    break
            else:
                res = f(*args, **kwargs)
                return res
        return wrapper
    return required
@required_types(int,float)    #这里的参数可以根据题目要求进行更改
def add(x, y):
    return x + y
print(add(1,2))


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页