代码编织梦想

对于很多刚刚接触Python的人来说,对装饰器的概念会感到非常模糊,因为几乎没有使用@作为语法标识的语言,本人唯一能想起来的也只有Java中的注释会以@来进行标识了。

装饰器是什么

装饰器是一种在不修改原函数的基础上给函数增加额外功能的方法。
在翻看别人的Python源代码的过程中,你肯定见到过一些这样的用法

# 有这样的
@decorator1
def add(x, y):
    return x + y

# 也有这样的
@decorator2(arg1, arg2)
def add(x, y):
    return x + y

在上面的代码中,两行以@开头的代码@decorator1@decorator2(arg1, arg2)就是我们今天要介绍的主角——装饰器

装饰器能做些什么

常见的装饰器功能分为如下几种:

  1. 记录函数的执行时间
  2. 记录函数的调用次数
  3. 缓存函数的结果
  4. 权限控制
  5. 类型检查

装饰器的原理是什么

首先我们要明确一个概念,在Python中,万物皆对象,所有东西其实都是object,函数也不例外。
装饰器的本质就是一个函数,它接受一个函数作为参数,并返回一个新的函数。
原函数可以在新函数内部被调用,并且新函数可以在原函数之前或之后添加新的功能。

当使用@decorator语法将装饰器应用于一个函数时,Python会执行如下操作:

  1. 首先调用装饰器函数,将原函数作为参数传入
  2. 装饰器函数返回一个新函数,并将原函数包装在新函数中
  3. Python 会将原函数的定义替换为新函数的定义

写个简单的装饰器吧

说了这么多的理论,接下来实战一下吧。
有没有这样一种需求,我们在执行代码时,想要知道某函数耗时是多少。通常第一反应想到的是如下实现方法

import time

def my_func():
    start = time.time()
    
    # 程序的主逻辑
    ...
    
    end = time.time()
    print(f"function 'my_func' spend {end - start} second.")

my_func()

# function 'my_func' spend x.xxxx seconds.

一个函数还好说,如果我们有多个函数都需要进行计时,岂不是要复制好几份代码了?这可一点也不Pythonic!
如果引入装饰器那就不同了,代码一下子就能变得清晰易读(省的后人骂你)。想对哪个函数计时,直接在这个函数头上加个计时装饰器就可以了。

import time

def timer(func):
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(f"function '{func.__name__}' spend {end - start} seconds.")
    return wrapper

@timer                  # 添加计时用装饰器
def sleep_3():
    time.sleep(3)
    
@timer                  # 添加计时用装饰器
def sleep_5():
    time.sleep(5)

sleep_3()
sleep_5()

# function 'sleep_3' spend 3.0012123584747314 seconds.
# function 'sleep_5' spend 5.0002405643463135 seconds.

我们来分析下这个例子

其实很好理解,其实等于将计时的核心逻辑抽象出来进行了复用。
sleep_3函数举例,在添加装饰器后,等价调用形式变为了timer(sleep_3())。所以装饰器只做了以下三件事:

  1. 将原有函数逻辑保存在timer函数的func参数中。
  2. 装饰器通过return wrapper,将sleep_3的功能重定向到了装饰器内部的wrapper函数。
  3. 将原有函数逻辑func插入在wrapper函数计时逻辑的中间运行。

看到这里就有人说了,上面的两个例子的函数都没有传参,平时使用函数基本都需要传递参数,但是加上参数这个装饰器就会报错,是不是写的有问题?
别急,我们继续往下看。

写个复杂点的装饰器

其实上面这个装饰器是最简单的版本(阉割版),下面我们来实现更加完整的pro版。
换个需求,这次我们还是需要打印函数运行的耗时,只不过这次的函数会带有参数,并且参数的情况不确定。接下来我们对装饰器进行下改造。

import time

def timer(func):
    def wrapper(*args, **kwargs):       # 给内部函数
        start = time.time()
        ret = func(*args, **kwargs)
        end = time.time()
        print(f"function '{func.__name__}' spend {end - start} seconds.")
        return ret
    return wrapper

@timer                  # 添加计时用装饰器
def add(x, y):
    return x + y
    
@timer                  # 添加计时用装饰器
def square(x):
    return x ** 2

print(add(1, 2))
print(square(3))

# function 'add' spend 1.0006356239318848 seconds.
# 3
# function 'square' spend 2.000314474105835 seconds.
# 9

按照惯例,我们来分析下这个例子

其实这个例子只是在上个例子的基础上,对被装饰的函数支持了传参的操作,核心仍是将计时的核心逻辑抽象了出来。
以函数add举例,在添加装饰器后,等价调用形式变为了timer(add(x, y))
而在装饰器内部,发生了以下几件事:

  1. 将原有函数逻辑保存在timer函数的func参数中。
  2. 装饰器通过return wrapper,将sleep_3的功能重定向到了装饰器内部的wrapper函数。
  3. 由于函数进行了重定向,原有add函数中的形参就被传递给了重定向后的函数wrapper,再将原有函数逻辑func插入在wrapper函数计时逻辑的中间运行。

最终经过装饰的函数,也会返回原函数add的执行结果,也就做到了一个使用无感可传参的装饰器。

看到这里有人就说了,装饰器大部分时间都被定义成了一个全局的命名空间进行使用,也就是定义在文件当中的最外层。但是我们也都知道,并非所有的东西都是适合放到全局的命名空间当中。
是不是你也遇到过这种需求,有很多装饰器想给他们分类和封装到类中,或者希望将其中的某些装饰器抽象到类中
不知道你是不是也曾经和我一样,尝试翻遍了全网的教程,但最终还是由于各种坑放弃了。
别急关注我,下面一篇你就会知道,原来实现的方式这么简单!

关注公众号

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/li63033/article/details/128764804

python基础——装饰器,语法糖_赵英杰的博客-爱代码爱编程

装饰器就是用闭包的方式,在给一个函数添加上下文,语法糖就是在要装饰的函数上边加上一个”@“符号加上装饰器函数名,挨着被装饰的函数近的语法糖先执行: def diguo(): print("底锅50") return 50 def doupi(f): def caidan1(): print("豆皮麻资10块")

python语法——@装饰器详解_happyrocking的博客-爱代码爱编程

python的装饰器其实就是一个以函数作为参数并返回一个替换函数的可执行函数。 装饰器用到了闭包原理,目的是为了简化代码,用@来表示。 不带参数的装饰器 我们从一个最简单的装饰器例子说起: def add_one(f

python中django 判断用户唯一在线 ,登录状态 的语法糖——装饰器心得_薄荷芯凉的博客-爱代码爱编程

这里先介绍一下啥是语法糖:语法糖指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。在python中 装饰器就是 一种语法糖,听着很甜蜜,用着更好使。 在介绍一下装饰器:装饰器是Python语言中的高级语法。主要的功能是对一个函数、方法、或者类进行加工,作用是为已经存

python基础笔记——装饰器(举例)-爱代码爱编程

装饰器 1、为原函数增加功能,但是不能修改原函数。 2、不能修改原函数调用方式。 1、 import time def timmer(func): def Warp(*args,**kwargs):

python语法——装饰器-爱代码爱编程

装饰器:给已有函数增加额外功能的函数,它本质上就是一个闭包函数。 在不改变已有函数源代码及调用方式的前提下,对已有函数进行功能的扩展。 特点: 不修改已有函数的源代码 不修改已有函数的调用方式 给已有函数增加额外的功能 # 装饰器的基本雏形 # def decorator(fn): # fn:目标函数. # def in

python类中的装饰器_Python 小技巧 —— 用类写装饰器-爱代码爱编程

最近学到了一个有趣的装饰器写法,就记录一下。 装饰器是一个返回函数的函数。写一个装饰器,除了最常见的在函数中定义函数以外,Python还允许使用类来定义一个装饰器。 1、用类写装饰器 下面用常见的写法实现了一个缓存装饰器。 def cache(func): data = {} def wrapper(*args, **kwargs): key = f'{f

python高级语法装饰器_Python高级编程——装饰器Decorator超详细讲解上-爱代码爱编程

Python高级编程——装饰器Decorator超详细讲解(上篇) 送你小心心记得关注我哦!! 进入正文 全文摘要 装饰器decorator,是python语言的重要特性,我们平时都会遇到,无论是面向对象的设计或者是使用相关的库,但是很少有文章对装饰器的来龙去脉进行深入详解,导致的结果就是很多人知其然,不知其所以然,所以我打算出一期关于Python装饰

python无参数装饰器_Python学习————无参装饰器-爱代码爱编程

一:储备知识 1、 *args, **kwargs def index(x,y): print(x,y) def wrapper(*args,**kwargs): index(*args,**kwargs) # index(y=222,x=111) wrapper(y=222,x=111) 2、名称空间与作用域:名称空间的的"嵌套"关系

python装饰器实现的函数重写_python之路——装饰器函数-爱代码爱编程

阅读目录 楔子 作为一个会写函数的python开发,我们从今天开始要去公司上班了。写了一个函数,就交给其他开发用了。 deffunc1():print('in func1') 季度末,公司的领导要给大家发绩效奖金了,就提议对这段日子所有人开发的成果进行审核,审核的标准是什么呢?就是统计每个函数的执行时间。 这个时候你要怎么做呀? 你一想,这

python基础装饰器_Python基础——装饰器、模块(0417)-爱代码爱编程

一、Python基础——复习 1、字符串的常用操作 2、列表的常用操作 3、字典的常用操作 二、Python——装饰器:函数可以是变量 1、Python是一种面向对象的编程语言,在Python中所有的都可以是Python的对象。即可以在函数内创建函数——函数也可以是变量!(亦可称之为:内嵌函数) 2、如果内部函数引用了外部函数定义的对象(即

python装饰器编程_Python高级编程——装饰器Decorator详解(上篇)(绝对是我见过最详细的的教程,没有之一哦)...-爱代码爱编程

一、先从一种情况开始看起 1、装饰器decorator的由来 装饰器的定义很是抽象,我们来看一个小例子。 先定义一个简单的函数: def myfunc: print('我是函数myfunc') myfunc() #调用函数 然后呢,我想看看这个函数执行这个函数用了多长时间,好吧,那么我们可以这样做: import time d

Python高级语法之——闭包和装饰器-爱代码爱编程

文章目录 闭包一个简单的例子装饰器1. 简单装饰器1. why 装饰器?2. 一个简单的例子:3. 使用装饰器的语法糖4. 装饰器的执行时机2. 通用装饰器1. 装饰带有参数的函数2. 装饰带有返回值的函数:3. 实现通用装饰器3. 多个装饰器的使用4. 带有参数的装饰器5. 类装饰器 闭包 闭包的形成条件: 函数嵌套。内部函数使用了外部函

Python基础5——装饰器-爱代码爱编程

13、装饰器 其本质:在不需要做任何代码变动的前提下,增加额外的功能。装饰器返回的是一个函数对象。 相当于把函数作为参数传递进去,然后对函数进行装饰 其本质就是一个闭包 作用: 给原来的函数增加额外的功能把原来的函数作为参数传递进去13.1 基本用法 标准版的装饰器 def wrapper(func): #func为原来的函数名 de

python三大器——装饰器_fei.y_1995的博客-爱代码爱编程

1 装饰器的引入 在日常需求开发中,假使我们需要对已经开发上线的程序添加某些功能,但是又不能对程序中函数的源代码进行修改,该如何处理呢?此时,就需要使用到Python中的装饰器(Decorator)。 2 Python闭

python的装饰器_苏茂林别干饭了的博客-爱代码爱编程

前言:     🤡 作者简介:我是Morning,计算机的打工人,想要翻身做主人 🙈 🙈 🙈     🏠 个人主页:Morning的主页     📕系列专栏::Morning的Python专栏     📞 如果小编的内容有欠缺或者有改进,请指正拙著。期待与大家的交流     🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏

python(五):python高级语法——装饰器_x@w1-爱代码爱编程

装饰器 1、函数名与变量 #### 一、 #### def foo(): print('foo') foo # 表示是函数 foo() # 表示执行foo函数 #### 二、 #### def foo(): print('foo') foo = lambda x: x + 1 foo() # 执行lambda表达式,而不再