首页 > 其他分享 >装饰器 原理

装饰器 原理

时间:2023-08-29 14:44:07浏览次数:33  
标签:func1 end begin wrapper outer time 原理 装饰

# 装饰器是用来装饰方法的,其作用就是在原函数的基础上,扩展功能。
#之所以要采用装饰器,是因为开放封闭原则,对修改封闭,对扩展开放。也就是说, 新功能的添加不能修改旧代码的执行逻辑和调用方式

import time
def func1(n=1):
  print(f"run start")
  time.sleep(n)
  print(f"run end")

#需求:统计该函数执行的时间。我们将通过以下7步实现装饰器实现原理的流程演示

# 修改方式1: 直接在函数调用处,添加扩展代码,这样不会修改源代码,如果有多个地方调用, 会造成重复代码过多,代码冗余。

begin = time.time()
func1(2)
end = time.time()
print(end-begin)

begin = time.time()
func1(2)
end = time.time()
print(end-begin)

begin = time.time()
func1(2)
end = time.time()
print(end-begin)

 

# 修改方式2, 在方式1的基础上,将调用的方式封装成方法,减少重复代码
# 带来的有点就是减少了重复代码,但是函数的参数被固化了,如果func1的参数修改了,就会报错。

def wrapper(n):
    begin = time.time()
    func1(n)
    end = time.time()
    print(end - begin)
wrapper(2)

 

#修改方式3, 在方式2的基础上,利用可变参数对其进行修改
#这种方式,可以完美解决函数入参的修改,但是固化了统计代码执行时间的方法,兵器而只能在func1上使用,如果我们想在func2上也使用该方法的话。那就在加一个wrapper方法。

def wrapper(*args, **kwargs):
    begin = time.time()
    func1(*args, **kwargs)
    end = time.time()
    print(end - begin)
wrapper(2)

 


#修改方式4,在方式3的基础,再进行封装,使其能够再多个方法上添加该功能
#这里的func1是在wrapper中,属于wrapper方法的局部名称空间,我们要将函数名传入,传入方式有两种,一种是以入参的方式传入,另一种方式就是闭包。
# 可变入参被完整的作为func1的入参传递,无法再将func1作为变量名传入,因此考虑第二种闭包方式传参。为了能够执行,将wrapper进行返回,切记不带括号,带括号就是返回的wrapper的执行结果

def outer():
    func_name = func1
    def wrapper(*args, **kwargs):
        begin = time.time()
        func_name(*args, **kwargs)
        end = time.time()
        print(end - begin)
    return wrapper
insper = outer()
insper(2)
# outer()==>insper   insper(2)==> wrapper(2)
#  为了可以在多个方法上进行扩展,将func_name的值提取出来作为外部函数的入参
def outer(func_name):
    def wrapper(*args, **kwargs):
        begin = time.time()
        func_name(*args, **kwargs)
        end = time.time()
        print(end - begin)
    return wrapper
insper = outer(func1)
insper(2)

# # outer()==>insper   insper(2)==> wrapper(2)

 

#修改方式5,在方式4的基础,我们已经基本上完成了对函数功能的封装。也可以在多个函数上重复使用该功能。
# 但是现在的调用,不满足我们的开放封闭原则,因为调用方式发生了修改,因此,为了保证调用方式不发生修改,我们再对其进行变形
#outer()的返回值wrapper,就是包装后的func1,表示的是方法的地址,无论命名成什么都可以,为了不修改调用方式,我们将outer()的返回值赋值给func1,就可以保证可最初的调用方式保持一致。
#虽然表面看起来一样,但是其本质已经发生了改变,如果我们将func1被装饰前后的地址打印出来,就会发现,两次的内存地址完全不一样。

def outer(func_name):
    def wrapper(*args, **kwargs):
        begin = time.time()
        func_name(*args, **kwargs)
        end = time.time()
        print(end - begin)
    return wrapper
func1 = outer(func1)
func1(2)

 

#修改方式6:修改方式5已经完成了装饰器的基本功能,但是还是有一个缺点,它把函数的返回值给弄丢了,如果func1有返回值的话,按照上边的执行逻辑,是拿不到他的执行结果的。因此还需最后一次变形

# 这就是装饰器最后的完整形态
def outer(func_name):
    def wrapper(*args, **kwargs):
        begin = time.time()
        rlt  = func_name(*args, **kwargs)
        end = time.time()
        print(end - begin)
        return rlt
    return wrapper

func1 = outer(func1)
func1(2)

 

#修改方式7 python解释器为了简化上边代码的编写。提供了语法糖的写法,也就是上边的代码的简化写法

def outer(func_name):
    def wrapper(*args, **kwargs):
        begin = time.time()
        rlt  = func_name(*args, **kwargs)
        end = time.time()
        print(end - begin)
        return rlt
    return wrapper

@outer
def func2():
    print("干饭去")
    time.sleep(1)
    print("干饭完成")

func2()

 

标签:func1,end,begin,wrapper,outer,time,原理,装饰
From: https://www.cnblogs.com/lhg37927/p/17664722.html

相关文章

  • 原来笔记本一直插着电源使用比较好 工作原理3张图秒懂
    热搜内容提到:原来笔记本一直插着电源使用比较好!笔记本电脑在充满电后使用,电源适配器将继续为电脑供电,而充满电的内置电池则不会继续工作,并不会出现一边充电、一边放电的情况。据了解,笔记本电脑里的锂电池没有记忆效应,而且正规厂家生产的锂电池都有相当完善的BMS(电池管理系统),......
  • FPGA芯片结构介绍及工作原理解析
     FPGA工作原理与简介  如前所述,FPGA是在PAL、GAL、EPLD、CPLD等可编程器件的基础上进一步发展的产物。它是作为ASIC领域中的一种半定制电路而出现的,即解决了定制电路的不足,又克服了原有可编程器件门电路有限的缺点。  由于FPGA需要被反复烧写,它实现组合逻辑的基本结构不......
  • 基于SpringBoot的装饰工程管理系统
    如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统装饰工程项目信息管理难度大,容错率低,管理人员处理数据费工费时,所以专门为解决这个难题开发了一个装饰工程管理系统项目立......
  • 08 IPv4地址协议以及网络层工作原理
    IP地址表示一个IPv4地址有32bit。一个IPv4地址有32bit。IP构成网络部分:用来标识一个网络,IP地址不能反映任何有关主机位置的地理信息,只能通过网络号码字段判断出主机属于哪个网络,IP地址不能反映任何有关主机位置的地理信息,只能通过网络号码字段判断出主机属于哪个网络......
  • SpringBoot - 原理
    目录配置文件优先级配置文件优先级虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置(yml是主流)IDEA配置系统属性和命令行参数:命令行参数>系统属性总体优先级:命令行参数优先级>系统属性>application.properties>application.y......
  • MySQL online DDl原理
    onlineDDL从5.6开始,不阻塞DML但是会阻塞所有的DDL,online有三种模式:INSTANT(8.0.12),INPLACE(rebuild),INPLACE(no-rebuild),具体操作如下:1、只修改表的元数据信息删除二级索引修改索引名(5.7)修改字段名设置(删除)字段的默认值增加varchar长度,如果表示字符串长度的字节数变化则会使用c......
  • 从原理聊 JVM(五):JVM 的编译过程和优化手段
    一、前端编译前端编译就是将Java源码文件编译成Class文件的过程,编译过程分为4步:1准备初始化插入式注解处理器(AnnotationProcessingTool)。2解析与填充符号表将源代码的字符流转变为标记(Token)集合,构造出抽象语法树(AST)。抽象语法树每个节点都代表着程序代码中的一个语法结......
  • 三河凡科科技飞讯教学篇:振弦采集读数模块开发原理详细介绍
    三河凡科科技飞讯教学篇:振弦采集读数模块开发原理详细介绍振弦采集读数模块是一种用于采集弦振信息的模块,其原理是通过传感器感知弦的振动,将其转化为电信号,然后经过模拟处理和数字化处理,最终输出为可供后续处理的数字信号。 振弦采集读数模块由三个主要部分构成:传感器、模拟......
  • 振弦采集读数模块开发原理详细介绍
    飞讯教学篇:振弦采集读数模块开发原理详细介绍振弦采集读数模块是一种用于采集弦振信息的模块,其原理是通过传感器感知弦的振动,将其转化为电信号,然后经过模拟处理和数字化处理,最终输出为可供后续处理的数字信号。振弦采集读数模块由三个主要部分构成:传感器、模拟处理电路和数字信号处......
  • 从原理聊JVM(五):JVM的编译过程和优化手段 | 京东云技术团队
    一、前端编译前端编译就是将Java源码文件编译成Class文件的过程,编译过程分为4步:1准备初始化插入式注解处理器(AnnotationProcessingTool)。2解析与填充符号表将源代码的字符流转变为标记(Token)集合,构造出抽象语法树(AST)。抽象语法树每个节点都代表着程序代码中的一个语法结构,包含包......