Python之装饰器(定义、调用方式、传参、应用)

1、什么是装饰器?

装饰器定义:
把一个函数当作参数,返回一个替代版的函数
本质上就是一个返回函数的函数
装饰器作用:
“在不改变原函数的基础上,给函数增加功能”

需求:在fun函数中添加#行内容
方法一:函数可能被其它模块已经调用,所以不能直接更改原函数

def fun():
    #print('Welcome to westos')		##在函数内直接添加
    print('Hello python!')

print('Welcome to westos')	##在函数之外添加需求信息,不适用已被调用的函数
fun()

Python之装饰器(定义、调用方式、传参、应用)_第1张图片
方法二:增加函数,调用时需要改函数名称

def fun():
    print('Hello python!')
    
def fun1():
    print('Welcome to westos')
    fun()

fun1()

Python之装饰器(定义、调用方式、传参、应用)_第2张图片
方法三:装饰器

def decorator(fun):	##定义装饰器函数
    def wrapper(*args,**kwargs):定义装饰器内部函数
        print('Welcome to westos')	##打印输出
        fun()			##调用函数
    return wrapper

@decorator	##使用装饰器给fun函数添加需求
def fun():
    print('Hello python!')

fun()

注意:
decorator是用于返回wrapper(不带()表示返回函数,带()表示返回运行结果)
Python之装饰器(定义、调用方式、传参、应用)_第3张图片

2、装饰器的调用方式

需求:在函数运行前打印时间

import time
def decorator(fun):
    def wrapper():
        print(time.time())	##打印linux系统时间,从1970年1月1日开始计算时间
        fun()
    return wrapper

def f1():
    print('This is a function')

f = decorator(f1)	##调用装饰器方式一,写在函数后面
f()

Python之装饰器(定义、调用方式、传参、应用)_第4张图片

import time
def decorator(fun):
    def wrapper():
        print(time.time())
        fun()
    return wrapper
@decorator	##调用装饰器方式二,写在函数前面
def f1():
    print('This is a function')
f1()

Python之装饰器(定义、调用方式、传参、应用)_第5张图片

3、装饰器传参

装饰器可以设置可变参数

import time
def decorator(func):
    def wrapper(*args,**kwargs):
        print(time.time())
        func(*args,**kwargs)
    return wrapper

@decorator
def f1(func_name):
    print('This is a function ' + func_name)

@decorator
def f2(func_name1,func_name2):
    print('This is a function ' + func_name1)
    print('This is a function ' + func_name2)
   
f1('test')
f2('test1','test2')

Python之装饰器(定义、调用方式、传参、应用)_第6张图片
装饰器可以设置关键字参数

import time
def decorator(func):
    def wrapper(*args,**kwargs):
        print(time.time())
        func(*args,**kwargs)
    return wrapper
@decorator
def f3(func_name1,func_name2,**kwargs):
    print('This is a function ' + func_name1)
    print('This is a function ' + func_name2)
    print(kwargs)
    
f3('test1','test2',a=1,b=2,c='westos')

Python之装饰器(定义、调用方式、传参、应用)_第7张图片

4、装饰器应用

应用一:装饰器实现一个函数计时器,计算函数运行时间
注意:
被装饰的函数有返回值时,需要在装饰器中对函数的运行结果处理(用一个变量保存函数 ,返回返回值)
用列表方式实现计算2 * n函数的时间
用高阶函数和匿名函数方式实现计算2 * n所用的时间

import time

def timetest(fun):
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = fun(*args,**kwargs)	##在装饰器中对函数的运行结果进行处理
        end_time = time.time()
        print('Running time is: %.6f' %(end_time - start_time))
        return res
    return wrapper

@timetest	##调用装饰器
def fun_list(n):	##列表方式
    """This is the fun_list function"""
    return [2 * i for i in range(n)]

@timetest
def fun_map(n):	##高阶函数方式
    """This is the fun_map function"""
    return list(map(lambda x:x*2,range(n)))

print(fun_list(100))
print(fun_map(100))

可以看出列表生成式的运行时间更短
Python之装饰器(定义、调用方式、传参、应用)_第8张图片
如何保留被装饰函数的函数名和帮助信息文档

import time
import functools	##导入函数工具

def timetest(fun):
    """This is a decorator fun"""
    @functools.wraps(fun)	##保留被装饰的函数名和帮助信息文档,否则默认返回wrapper函数的帮助信息文档
    def wrapper(*args,**kwargs):
        """This is a wrapper function"""
        start_time = time.time()
        res = fun(*args,**kwargs)	
        end_time = time.time()
        print('Running time is: %.6f' %(end_time - start_time))
        return res
    return wrapper

@timetest
def fun_list(n):	
    """This is the fun_list function"""
    return [2 * i for i in range(n)]

@timetest
def fun_map(n):

    """This is the fun_map function"""
    return list(map(lambda x:x*2,range(n)))

print(fun_list.__doc__)		##打印函数帮助信息
print(fun_list.__name__)	##打印函数名

Python之装饰器(定义、调用方式、传参、应用)_第9张图片
应用二:
创建装饰器, 要求如下:

  1. 创建add_log装饰器, 被装饰的函数打印日志信息;
  2. 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx
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,10)

在这里插入图片描述
应用三:
编写装饰器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(*kind):
    def required(fun):
        @functools.wraps(fun)
        def wrapper(*args,**kwargs):
            for i in args:
                if not isinstance(i,kind):
                    print('TypeError:参数必须为%s,%s类型' %kind)
                    exit()
            else:
                res = fun(*args,**kwargs)
                return res
        return wrapper
    return required

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

print(add(1.0,2))	##对应第一张图
print(add(1.0,2.0))	##对应第二张图

在这里插入图片描述
Python之装饰器(定义、调用方式、传参、应用)_第10张图片
应用四:
多个装饰器运用

def decorator_a(fun):
    def inner_a(*args,**kwargs):
        print('This is inner_a')
        return fun(*args,**kwargs)
    return inner_a

def decorator_b(fun):
    def inner_b(*args,**kwargs):
        print('This is inner_b')
        return fun(*args,**kwargs)
    return inner_b

@decorator_b
@decorator_a
def f(x):
    print('This is f')
    return x*2

print(f(1))

Python之装饰器(定义、调用方式、传参、应用)_第11张图片

你可能感兴趣的:(Python之装饰器(定义、调用方式、传参、应用))