python学习笔记------装饰器进阶

装饰器进阶

is_admin装饰器:判断传入的参数是否root;

import functools
import inspect

# 利用inspect函数可以获取类中的docs,类名,类以及类的代码,是否存在的模块等等。

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("not root/admin user, no permisson add student")   # 抛出异常
    return wrapper


@is_admin   # add_student = is_admin(add_student)
def add_student(name):   #
    print("添加学生信息.....")
add_student('redhat')
add_student('root')



inspect的返回值: {'name': 'redhat'}
not root/admin user, no permisson add student
inspect的返回值: {'name': 'root'}
添加学生信息.....

探究多个装饰器的执行顺序

def decorator_a(func):
    print('Get in decorator_a')
    def inner_a(*args, **kwargs):
        print('Get in inner_a')
        return func(*args, **kwargs)
    return inner_a

def decorator_b(func):
    print('Get in decorator_b')
    def inner_b(*args, **kwargs):
        print('Get in inner_b')
        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)


Get in decorator_a
Get in decorator_b
Get in inner_b
Get in inner_a
Get in f

多个装饰器的应用

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

import functools
import inspect


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

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


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('aa')
add_student('redhat')
add_student('root')


Error: aa未登陆!
inspect的返回值: {'name': 'redhat'}
Error:not root/admin user, no permisson add student
inspect的返回值: {'name': 'root'}
添加学生信息.....

带参数的装饰器

import time
import functools
import random

# 带有参数的装饰器; 在原有装饰器外面加一个函数, 用来接收装饰器参数的;
def addLog(type):   # type='warn'
    # type="warn"    Warn
    # type.title()
    def add_log(f):
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            start_time = time.time()
            res = f(*args, **kwargs)
            end_time = time.time()
            print("日志信息:[%s] [%s] %s 运行时间为%.5f s 运行结果为%s" %(type.title(),time.ctime(),f.__name__,end_time-start_time,res))
            return res
        return wrapper
    return add_log


@addLog("warn")   # hello = addLog(warn')
                        #  hello = add_log(hello)
                        # hello ======= wrapper()
def hello():
    time.sleep(random.random())
    return "hello"


@addLog(type="debug")
def add(x,y):
    time.sleep(random.random())
    return x+y

print(hello())
print(add(1,2))


日志信息:[Warn] [Wed Aug 29 19:28:05 2018] hello 运行时间为0.79795 s 运行结果为hello
hello
日志信息:[Debug] [Wed Aug 29 19:28:06 2018] add 运行时间为0.76612 s 运行结果为3
3

带有参数装饰器的练习–参数检测

# 1. 基础版(无参数的装饰器)
编写装饰器required_ints, 条件如下:
    1). 确保函数接收到的每一个参数都是整数;
    2). 如果参数不是整形数, 打印 TypeError:参数必须为整形

# 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, 2e+9))

装饰器总结

# 装饰器函数不加参数:
def 装饰器名称(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        # 函数执行之前做的操作
        res =  fun(*args, **kwargs)
        # 函数执行之前做的操作
        return res
    return wrapper


# 装饰器函数加参数:
def  装饰器名称(*args, **kwargs):
    def inner(fun):
        @functools.wraps(fun)
        def wrapper(*args, **kwargs):
            # 函数执行之前做的操作
            res =  fun(*args, **kwargs)
            # 函数执行之前做的操作
            return res
        return wrapper
    return inner


# import functools     
    @functools.wraps(f)

# functools.wraps(fun): 可以保留add, world等函数的函数名, 帮助文档等属性信息;


# import inspect
inspect.getcallargs(f,*args,**kwargs)

# inspect.getcallargs返回一个字典, key值为:形参, value值为对应的实参;


猜你喜欢

转载自blog.csdn.net/qq_41891803/article/details/82191463