一.装饰器

1.定义:
把一个函数当作参数,返回一个替代版的函数
本质就是一个返回函数的函数

也指在不改变原函数的基础上,给函数增加功能

举例如下:
Python——装饰器及其练习
装饰器的使用如下:

def desc(fun):     ##装饰器
    def add_info():   装饰器内部函数
        print('清明节快乐~')
        fun()   ##调用的函数
    return add_info  


@desc    ##给该函数添加装饰器
def login():
    print('login...')
@desc
def logout():
    print('logout...')

login()   #该函数的执行过程:在执行该函数时先返回该函数,发现该函数需要装饰器,再返回装饰器 ,首先识别return add_info 返回装饰器内部函数,执行装饰器内部要添加的内容,然后再执行该函数 
logout()

Python——装饰器及其练习

效果如下:
Python——装饰器及其练习
2.特性

  • 对修改时封闭的,对扩展时开放的

导入时间:(导入的是linux系统的时间)
Python——装饰器及其练习

举例如下:
Python——装饰器及其练习
效果如下:
Python——装饰器及其练习
上述例子添加装饰器优化如下:
当函数f1有装饰器,而f2没有装饰器时:
Python——装饰器及其练习
效果如下:
Python——装饰器及其练习
3.装饰器设置可变形参

举例说明如下:
Python——装饰器及其练习
效果如下:
Python——装饰器及其练习
4.装饰器设置关键字参数

举例说明如下:
Python——装饰器及其练习
效果如下:
Python——装饰器及其练习
5.装饰器练习1

  • 装饰器实现一个函数计时器

问题1:被装饰的函数有返回值

问题2:如何保留被装饰函数的函数名和帮助信息文档

实现如下:

import time
import random
import string
import functools   ##导入帮助文档
li = [random.choice(string.ascii_letters) for i in range(100)]    ##产生内推码
print(li)

def Timer(fun):
    """这是一个装饰器"""
    @functools.wraps(fun)  ##帮助文档的调用
    def wrapper(*args,**kwargs):
        """这是一个wrapper函数"""
        start_time = time.time()
        res = fun(*args,**kwargs)
        end_time = time.time()
        print('运行时间为:%.5f' %(end_time-start_time))
        return res
    return wrapper
@Timer
def con_add():
    s = ''
    for i in li:
        s += (i + ',')
    print(s)
@Timer
def join_add():
    print(','.join(li))
@Timer
def fun_list(n):
    """这是一个fun_list函数"""
    return [i ** 2 for i in range(n)]
@Timer
def fun_map(n):
    return list(map(lambda x:x**2,range(n)))
con_add()
join_add()
print(fun_list(100))
print(fun_map(100))

运行如下:

  • 不带函数返回值的
    Python——装饰器及其练习
  • 带有返回数值的
    注意:当函数带有返回值时,要在装饰器内部添加其返回值
 res = fun(*args,**kwargs)   ##在装饰器内部将返回值赋值个给一个变量
 return res  #最后返回该数值

Python——装饰器及其练习

  • 返回帮助文档的
    注意:添加帮助文档后如果在执行某函数时使用帮助文档的参数,则会显示该函数的帮助文档
    Python——装饰器及其练习
  • 注释掉帮助文档
    注意:在注释掉帮助文档但是调用了帮助文档之后,则返回时显示的是装饰器内部的函数的信息
    Python——装饰器及其练习
  • 标准时间的生成
    Python——装饰器及其练习
    6.帮助文档的使用

举例如下:

import time
import functools

def add_log(fun):
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = fun(*args,**kwargs)
        end_time = time.time()
        print('[%s] 函数名: %s, 运行时间: %6f,运行返回值结果: %d' 
        %(time.ctime(),fun.__name__,(返回执行的函数的名字) end_time - start_time,res))
        return res
    return wrapper

@add_log
def add(x,y):
    time.sleep(1)
    return x + y

add(1,2)

Python——装饰器及其练习
6.装饰器练习2

  • 判断是否为管理用户登录,如果是root,则显示相应的信息

insepect.getcallargs返回一个字典,key值是形参,value值是对应的实参
Python——装饰器及其练习
Python——装饰器及其练习
效果如下:
Python——装饰器及其练习
7.装饰器设置可变参数

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

实现如下:

import functools


def required_types(*kinds):  ##设置装饰器接收多个参数
    def required_int(fun):
        @functools.wraps(fun)
        def wrapper(*args, **kwargs):
            for i in args:   ##编历参数
                if not isinstance(i, kinds):  #判断参数类型是否为函数中给定的并且传到装饰器的参数
                    # print('TypeError:参数必须为',kinds)
                    # break   
                    raise TypeError('参数必须为%s,%s' % kinds)
            else:
                res = fun(*args, **kwargs)
                return res

        return wrapper

    return required_int  ##给装饰器返回函数的指定的多个参数


@required_types(float, float)
def add(a, b):
    return a + b


print(add(1.1, 2.0))

Python——装饰器及其练习

  • 装饰器内部当报错返回值为print类型时的返回参数
    Python——装饰器及其练习
  • 当装饰器内部出错时使用raise返回参数
    Python——装饰器及其练习

二.多个装饰器

1.多个装饰器的实现及其内部的执行顺序
Python——装饰器及其练习
Python——装饰器及其练习
执行效果如下:
Python——装饰器及其练习
由上结果可得:当有多个装饰器时,当定义一个函数使用多个装饰器时,首先装饰器外部的调用是自底向上的,而内部函数则是自顶向下的。

可分析上述结果:首先是从装饰器b,在到装饰器b的时候,发现装饰器外部要print,则执行该步,然后在到a装饰器,发现在改装饰器的外部同样也要执行相应的print,在执行完后就到装饰器的内部函数,则先执行b装饰器内部函数的内容,然后再执行b装饰器内部函数的内容。

2.多个装饰器练习

import functools
import inspect

def is_admin(fun):
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):
        #inspect.getcallargs返回一个字典,key值是形参,value值
        #是对应的实参{'name':'root'}
        inspect_res = inspect.getcallargs(fun,*args,*kwargs)
        print('inspect的返回值: %s' %inspect_res)
        if inspect_res.get('name') == 'root':
            res = fun(*args,**kwargs)
            return res
        else:
            print('not root user!')
    return wrapper

login_session = ['root', 'redhat', 'westos']

def is_login(fun):
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):
        if args[0] in login_session:
            res = fun(*args,**kwargs)
            return res
        else:
            print('Error:%s未登录' %args[0])
    return wrapper



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

add_student('linux')

执行效果如下:
Python——装饰器及其练习

相关文章: