装饰器

装饰器

一.装饰器

1.装饰器简介

  • 概念

    在不改变被装饰对象原代码和调用方式的情况下给被装饰对象添加新的功能

  • 本质

    并不是一门新的技术 而是由函数参数、名称空间、函数名多种用法、闭包函数组合刀一起的结果

  • 口诀

    对修改封闭,对扩展开放

  • 储备知识

    时间相关操作

    import time
    print(time.time())  # 时间戳(距离1970-01-01 00:00:00所经历的秒数)
    time.sleep(3)  # 让程序等待三秒再执行
    print('休息三秒')
    
    count = 0
    # 循环之前先获取时间戳
    start_time = time.time()
    while count < 100:
        print('哈哈哈')
        count += 1
    end_time = time.time()
    print('循环消耗的时间:', end_time - start_time)
    
    

2.装饰器推导流程

import time

def index():
    time.sleep(3)
    print('from index')
    
index()

1.首先我们想统计index函数执行产生的时间戳

import time

def index():
    time.sleep(3)
    print('from index')
strat_time = time.time()
index()
end_time = time.time()
print('函数执行的时间:', end_time - strat_time)
# from index
index运行的时间: -3.007066249847412

2.由上可看出我们可以在调用函数index的前后添加代码,但是如果我们在其他地方多次调用函数index的时候,也需要查看时间戳,那么就需要多次输入以上代码,就显得多余费力,那么我们就要用到函数去定义这段代码方便调用

def get_time():
    strat_time = time.time()
    index()
    end_time = time.time()
    print('函数执行的时间:', end_time - strat_time)

get_time()

3.这样是方便以后调用查看,但是却给函数体代码写死了,如果有另一个函数也要统计时间要怎么查看呢,那么我们就需要直接传参变换统计的函数

import time

def index():
    time.sleep(3)
    print('from index')
def func():
    time.sleep(2)
    print('from func')

def get_time(a):
    strat_time = time.time()
    a()
    end_time = time.time()
    print('函数执行的时间:', end_time - strat_time)

get_time(index)
get_time(func)

"""
from index
函数执行的时间: -3.0028903484344482
from func
函数执行的时间: -2.0058066844940186
"""

4.实现了多个函数可用,但是却违背了装饰器规则,更改了调用方式,第一种传参不能用,我们要考虑闭包

def outer(b):
    # b = index
    def get_time():
        strat_time = time.time()
        b()
        end_time = time.time()
        print('函数执行的时间:', end_time - strat_time)
    return get_time
res = outer(index)
res()
res = outer(func)
res()
"""
from index
函数执行的时间: 3.0039374828338623
from func
函数执行的时间: 2.0016427040100098
"""

5.调用方式还是不对,如何去变形呢?我们考虑变量名赋值绑定,我们把res 直接换成函数名(其实就是在欺骗我们的眼睛)

def outer(b):
    # b = index
    def get_time():
        strat_time = time.time()
        b()
        end_time = time.time()
        print('函数执行的时间:', end_time - strat_time)
    return get_time
index = outer(index)  # 赋值符号的左边是一个变量名 可以随意命名
index()
func = outer(func)
func()
"""
from index
函数执行的时间: 3.0039374828338623
from func
函数执行的时间: 2.0016427040100098
"""

6.这时调用方式我们看起来就和之前一样了,但是!!!这只能装饰无参函数,兼容性太差,如果是有参函数呢?

import time

def index(a):
    time.sleep(3)
    print('from index', a)

def outer(b):
    # b = index
    def get_time(a):
        strat_time = time.time()
        b(a)
        end_time = time.time()
        print('函数执行的时间:', end_time - strat_time)
    return get_time
index = outer(index)
index(1)

7.以上只适用于只有一个形参的情况,如果是有多个参数或者没有参数,如何兼容

import time

def index(a):
    time.sleep(3)
    print('from index', a)
def index1(a, b):
    time.sleep(1)
    print('from index1', a, b)
def index2():
    time.sleep(1)
    print('from index2')
def outer(b):
    # b = index
    def get_time(*args, **kwargs):
        strat_time = time.time()
        b(*args, **kwargs)
        end_time = time.time()
        print('函数执行的时间:', end_time - strat_time)
    return get_time
index = outer(index)
index(1)
index1 = outer(index1)
index1(1, 2)
index2 = outer(index2)
index2()
"""
from index 1
函数执行的时间: 3.0133862495422363
from index1 1 2
函数执行的时间: 1.0149316787719727
from index2
函数执行的时间: 1.0117344856262207
"""

8.如果被执行函数有返回值

def func(a):
    time.sleep(0.1)
    print('from func', a)
    return 'func'
def func1(a,b):
    time.sleep(0.2)
    print('from func1', a, b)
    return 'func1'
def outer(xxx):
    def get_time(*args, **kwargs):
        start_time = time.time()
        res = xxx(*args, **kwargs)
        end_time = time.time()
        print('函数执行的时间>>>:', end_time - start_time)
        return res
    return get_time
func = outer(func)
res = func(123)
print(res)

func1 = outer(func1)
res = func1(123, 123)
print(res)

3.装饰器模板

def outer(func_name)
	def inner(*args, **kwargs)
    print('执行被装饰对象之前可以做的额外操作')
    res = func_name(*args, **kwargs)
    print('执行被装饰对象之后可以做的额外操作')
    return res
return inner

二.装饰器语法糖

1.基本语法糖

def outer(fucn_name):
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
"""
语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数调用
"""
@outer  # func = outer(func)
def func():
    print('from func')
    return 'func'
@outer  # index = outer(index)
def index():
    print('from index')
    return 'index'

func()
index()

2.多层语法糖

语法糖会将下面紧挨着的函数名当做第一个参数自动传给@函数调用

实际案例:

def outter1(func1):
    print('加载了outter1')
    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def outter2(func2):
    print('加载了outter2')
    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2

def outter3(func3):
    print('加载了outter3')
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3


@outter1
@outter2
@outter3
def index():
    print('from index')

image

三.有参装饰器

1.什么是有参装饰器:

给装饰器传递额外的参数,满足多个数据值的传输切换

2.实操

def outer(mode):
    def login(func_name):
        def inner(*args, **kwargs):
            username = input('username:').strip()
            password = input('password:').strip()
            if mode == '1':
                print('数据直接写死')
            elif mode == '2':
                print('数据来于列表')
            elif mode == '3':
                print('数据来自于字典')
            elif mode == '4':
                print('数据来自集合')
            elif mode == '5':
                print('数据来于文本文件')
        return inner
    return login


@outer('1')
def index():
    print('from index')
index()   

@outer('2') 
def func():
    print('from func')
func() 
"""
函数名加括号执行优先级最高 有参装饰器的情况
	先看函数名加括号的执行
	然后再试语法糖的操作
"""

3.装饰器模板

1.常用的无参装饰器模板

def outer(func_name):
    def inner(*args, **kwargs):
        '''被装饰函数执行前可做的额外的操作'''
        res = func_name(*args, **kwargs)
        '''被装饰函数执行后可做的额外操作'''
        return res
    return inner
@outer
def index():
    pass

2.不常用的有参装饰器

def outer_plus(mode):
	def outer(func_name):
		def inner(*args, **kwargs)
			res = func_name(*args, **kwargs)
			return res
		return inner
    return outer
@outer_plus('dict')
def func():
    pass

四.装饰器修复技术

1.了解知识

help() :在使用python来编写代码时,会经常使用python自带函数或模块,一些不常用的函数或是模块的用途不是很清楚,这时候就需要用到help函数来查看帮助。help()函数是查看函数或模块用途的详细说明。

def index():
    '''我是最棒的!!!'''
    pass
help(index)
结果:
Help on function index in module __main__:

index()
    我是最棒的!!!

2.装饰器修复技术

from functools import wraps
def outer(func_name):
    @wraps(func_name)
    def inner(*args, **kwargs):
        '''我是inner'''
        res = func_name(*args, **kwargs)
        return res
    return inner
    
@outer
def func():
	'''我是才是func'''
    pass

help(func)
print(func)
func()
posted @ 2022-10-12 17:29  dear丹  阅读(48)  评论(0编辑  收藏  举报