首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >装饰器--从入门到入土!

装饰器--从入门到入土!

作者头像
HammerZe
发布于 2022-03-25 12:09:56
发布于 2022-03-25 12:09:56
35500
代码可运行
举报
文章被收录于专栏:Hammer随笔Hammer随笔
运行总次数:0
代码可运行

目录

装饰器

本文讲述了装饰器由简易装饰器到完整装饰器的过程,一个段落解决一个问题!

1、定义

  • 器:指的是工具
  • 装饰:给被装饰对象添加额外的功能

2、原则

开放封闭的原则

  • 开放:对扩展开放
  • 封闭:对修改封闭

3、装饰器核心思想

在不改变被“装饰”对象内部代码原有调用方式的基础之上添加额外的功能。

实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 计算程序的执行时间
import time

# 获取的结果叫时间戳(运行代码的那一刻距离1970-1-1所经历的秒数)
print(time.time())


def index():
    time.sleep(3)
    print('计算时间停止了3秒后的结果!')


# 统计开始时间
start_time = time.time()
index()
# 统计结束的时间
end_time = time.time()
# 输出时间差
print(end_time-start_time)
# 时间运行的时间
print(end_time-start_time-3)

4、装饰器简易版本

实例如下: 使用闭包函数实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import time
# 定义普通无参函数
def func():
    time.sleep(2)
    print('正在执行func函数')


def get_func_name(func_name):
    # 将参数写入形参,可以灵活传参
    # func_name = func
  
   # 构造一个能够计算函数运行时间的闭包函数
    def get_time():
    # 获取开始时间
        start_time = time.time()
        # 调用函数
        func_name() # func_name()就是func()
        # 查看func_name指向的是哪个函数,方便理解
        print('func_name指向的是>>>:',func_name)
        # 获取结束时间
        end_time = time.time()
        # 打印运行时间
        print("函数执行时间为{0}".format(end_time-start_time))
    # 获取返回值
    print('get_time指向的是>>>:',get_time)
    return get_time  # 这里其实是把func

# 调用get_func_name函数,传参,res接收返回结果,返回值为get_time
res = get_func_name(func)
res()
# 获取res指向的是那个函数
print('res指向的是>>>:',res)

5、解决有参函数问题

由于简易版本的装饰器,只能装饰无参函数,为了让有参函数也能够被装饰,需要改进简易版本 实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import time
# 定义一个无参函数
def non_argument():
    time.sleep(1)
    print('执行的是无参函数')
# 定义一个有参函数
def have_argument(*args,**kwargs):
    time.sleep(1)
    print('执行的是有参函数,参数为:',*args,**kwargs)

def get_func_name(func_name):
    # func_name = non_argumengt
    def get_time(*args,**kwargs):
        start_time = time.time()
        func_name(*args,**kwargs)
        end_time = time.time()
        print('函数运行时间为:',end_time-start_time)
    return get_time

#调用无参函数
non_argument = get_func_name(non_argument)
non_argument()  # 这里的non_argument()其实指向的是get_time
# 打印查看一下,指向的是谁,此non_argument()非彼non_argument
print(non_argument)

# 调用有参函数
have_argument = get_func_name(have_argument)
have_argument('hammer',18)

6、解决返回值问题

为了解决能够装饰有返回值的有参、无参函数,计算它们的运行时间,升级装饰器为可以装饰有参、无参带返回值的装饰器,改进装饰器版本。 实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import time
# 定义一个无参函数
def non_argument():
    time.sleep(1)
    print('执行的是无参函数')
    return 'from non_argument'
# 定义一个有参函数
def have_argument(*args,**kwargs):
    time.sleep(1)
    print('执行的是有参函数,参数为:',*args,**kwargs)
    return 'from have_argument'

# 现在可以计算有参、无参、有返回值的函数执行时间
def get_func_name(func_name):   # func_name = non_argumengt

    def get_time(*args,**kwargs):
        start_time = time.time()
        # 用get_return 接收被装饰函数的返回值
        get_return = func_name(*args,**kwargs)
        end_time = time.time()
        print('函数运行时间为:',end_time-start_time)
        # 返回被装饰函数的返回值
        return get_return
    return get_time

# 调用装饰器,打印被装饰函数的运行时间,和返回值
non_argument = get_func_name(non_argument)
print(non_argument())

have_argument = get_func_name(have_argument)
print(have_argument())

返回值解决后,就会推出一个固定的格式,外层获取函数名不能改变,内层获取被装饰的参数( * args, * kwargs)不用改变。*

7、装饰器模板

装饰器经过多版本的升级,发现了一个规律,推出装饰器模板 实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def get_func_name(func_name):   # func_name = 函数名

    def get_time(*args,**kwargs):
        # 写入被装饰前的代码体
        '''代码体'''
        # 用get_return 接收被装饰函数的返回值
        get_return = func_name(*args,**kwargs)
        # 写入被装饰后的代码体
        '''代码体'''
        # 返回被装饰函数的返回值
        return get_return
    return get_time

8、认证装饰器

简易版认证装饰器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'''
在调用sign之前需要用户输入用户名和密码
    正确才可以调用
    错误直接拒绝
'''
import time


def sign():
    time.sleep(1)
    print('sign is running')
    return 'from sign'


def get_func_name(func_name):
    def get_func_argument(*args, **kwargs):
        username = input('please input your name>>>:').strip()
        password = input('please input your pwd>>>:').strip()
        if username == 'hammer' and password == '123':
            get_return = func_name(*args, **kwargs)
            print('>>>>>success!')
        else:
            print('>>>>>failure!')
        return get_return

    return get_func_argument


sign = get_func_name(sign)
print(sign())

多函数复杂认证装饰器:认证一个函数后面的函数不需要认证 实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import time


def sign():
    time.sleep(1)
    print('sign is running')
    return 'from sign'
def login():
    time.sleep(1)
    print('login is running')
    return 'from login'
def shopping():
    time.sleep(1)
    print('shopping is running ')
    return 'from shopping'


# 定义一个用于记录用户是否登录的数据,全局标志
is_login = {'is_login':False}
# 构造一个装饰器
def get_func_name(func_name):
    def get_func_argument(*args, **kwargs):
        # 判断用户是否登录
        # 登录过就直接运行被装饰的函数
        if is_login.get('is_login'):
            get_return = func_name(*args, **kwargs)
            print('>>>>>success!')
            return get_return

        username = input('please input your name>>>:').strip()
        password = input('please input your pwd>>>:').strip()
        if username == 'hammer' and password == '123':
            get_return = func_name(*args, **kwargs)
            # 用户如果登录成功将登录状态改成True
            is_login['is_login']= True
            print('>>>>>success!')
            return get_return
        else:
            print('>>>>>failure!')
        # return get_return
    return get_func_argument


sign = get_func_name(sign)
sign()

login = get_func_name(login)
login()

shopping = get_func_name(shopping)
shopping()

9、装饰器语法糖

格式:@装饰器 原理:会将下面紧贴的函数当成被装饰的对象 语法糖执行顺序:****被装饰的对象如果有多层语法糖,装饰的顺序由下向上

实例如下: eg:# @get_func_name 相当于 函数名()= get_func_name(函数名)

单层语法糖(重难点)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import time
# 现在可以计算有参、无参、有返回值的函数执行时间
def get_func_name(func_name):   # func_name = non_argumengt

    def get_time(*args,**kwargs):
        start_time = time.time()
        # 用get_return 接收被装饰函数的返回值
        get_return = func_name(*args,**kwargs)
        end_time = time.time()
        print('函数运行时间为:',end_time-start_time)
        # 返回被装饰函数的返回值
        return get_return
    return get_time


# 定义一个无参函数
@get_func_name
# @get_func_name 相当于 函数名= get_func_name(函数名)  
def non_argument():
    time.sleep(1)
    print('执行的是无参函数')
    return 'from non_argument'


non_argument()

双层语法糖(重难点)

实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 统计函数运行时间
import time
def get_time(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)  # 执行被装饰的函数
        end_time = time.time()
        print('函数执行时间:%s'%(end_time-start_time))
        return res  # 将被装饰函数执行之后的返回值返回
    return inner
# 校验用户登录装饰
def login_auth(func):
    def inner(*args, **kwargs):
        # 1.先获取用户的用户名和密码
        username = input('username>>>:').strip()
        password = input('password>>>:').strip()
        # 2.校验用户名和密码是否正确
        if username == 'jason' and password == '123':
            res = func(*args, **kwargs)  # 执行被装饰的函数
            return res  # 将被装饰函数执行之后的返回值返回
        print('用户名或密码错误 无权限执行')
    return inner
@login_auth
@get_time # get_time
def index():
    time.sleep(1)
    print('from index')
index()

三层语法糖(难点)

实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 判断七句print执行顺序
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')
    
# 结果
加载了outter3   
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index

  • 自己总结了一句话,在多层语法糖中,想要知道运行的顺序,一句话概括,外层局部函数由下向上执行,内层闭包函数由上向下执行,最后执行被装饰函数中的代码!~(个人理解不喜勿喷)
  • 装饰器由下往上,遇到最后一个语法糖才会使用与函数名相同的变量名(被装饰函数)

10、装饰器修复技术

  • 定义:装饰器修复技术,为了更好的掩藏被装饰对象更不被容易被察觉出用了装饰器。将返回的装饰器id换成真正函数id地址!
  • 格式
    • from functools import wraps
    • @wraps(函数名)

实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import time
from functools import wraps
# 现在可以计算有参、无参、有返回值的函数执行时间
def get_func_name(func_name):   # func_name = non_argumengt
    @wraps(func_name)
    def get_time(*args,**kwargs):
        start_time = time.time()
        # 用get_return 接收被装饰函数的返回值
        get_return = func_name(*args,**kwargs)
        end_time = time.time()
        print('函数运行时间为:',end_time-start_time)
        # 返回被装饰函数的返回值
        return get_return
    return get_time

# 定义一个无参函数
@get_func_name
def non_argument():
    time.sleep(1)
    print('执行的是无参函数')
    return 'from non_argument'
# 定义一个有参函数

@get_func_name
def have_argument(*args,**kwargs):
    time.sleep(1)
    print('执行的是有参函数,参数为:',*args,**kwargs)
    return 'from have_argument'

non_argument()
have_argument()

'''如果不写修复技术,调用装饰器打印的id地址为get_time()的id地址,写了之后查看id为被装饰函数的id地址'''

11、有参装饰器

实例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def outer(source_data):
    # source_data = 'file'
    def login_auth(func):
        def auth(*args,**kwargs):
            # 2.校验用户名和密码是否正确
            # 数据的校验方式可以切换多种
            if source_data == 'file':
                # 从文件中获取用户数据并比对
                print('file文件获取')
            elif source_data == 'MySQL':
                # 从MySQL数据库中获取数据比对
                print('MySQL数据库获取')
            elif source_data == 'postgreSQL':
                # 从postgreSQL数据库中获取数据对比
                print('postgreSQL数据库获取')
            else:
                print('用户名或密码错误 无法执行函数')
        return auth
    return login_auth

@outer('file')
def index():
    print('from index')
@outer('MySQL')
def home():
    print('from home')

index()
home()
持续更新中····
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-11-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
闭包函数和装饰器
闭包:闭是封闭(函数内部嵌套函数),包是包含,闭包是指该内部函数对外部作用域而非全局作用域的变量的引用。
GH
2022/05/10
4010
Python入门之函数的装饰器
本章目录:     装饰器:         一、为什么要用装饰器         二、什么是装饰器         三、无参装饰器         四、装饰器语法糖         五、认证装饰器实现         六、叠加多个装饰器         七、带参装饰器    =========================================================== 一、开放封闭原则   引子--为什么要用装饰器   软件一旦上线后,对修改源代码是封闭的,对功能扩展是开放的。  
Jetpropelledsnake21
2018/05/02
8800
Python入门之函数的装饰器
Python基础09-装饰器
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
DriverZeng
2022/09/26
2920
Python基础09-装饰器
Python之路【第七篇】:Python
阅读目录 一、装饰器 1、装饰器的概念 #装饰器定义:本质就是函数,功能是为其他函数添加附加功能 二、装饰器需要遵循的原则 #原则: 1、不修改被修饰函数的源代码 2、不修改被修饰函数的调用方式 装饰器他人的器具,本事可以是任意可调用对象,被装饰者也可以是任意可调用对象。 #强调装饰器的原则: 1、不修改被装饰对象的源代码 2、不修改被装饰对象的调用方式 #装饰器的目标: 在遵循1和2原则的前提下,为被装饰的对象添加新功能 三、实现装饰器知识储备 装饰器=高阶函数+函数嵌套+闭包 四、高阶函数 高阶函
py3study
2020/01/16
3320
【globlal与nonlocal和闭包函数、装饰器、语法糖】
在py文件中,一般无法调用函数体内变量名,而global可使函数体代码内的变量名直接在函数体外部调用,条件是在需要调用的代码体中使用global 调用需要的变量名 未使用global情况
老虎也淘气
2024/01/30
1590
Python Day3
#如果是windows平台一般还要加上一个小r,意思是取消路径中/的转义功能(不用写//了) #默认t,指的是文本文件,文本里面存放的是字符,因此涉及到字符编码,如果不指定使用什么字符编码打开就按默认操作系统默认编码打卡,windows默认GBK f=open(r'a.txt','r',encoding='utf-8') #读 #这一步说明发送了一个请求给操作系统,把某个文件已什么字符编码打开,同时还拿到了一个变量f
py3study
2020/01/03
5930
6.Python装饰器
​ 什么是开放封闭原则?有的同学问开放,封闭这是两个反义词这还能组成一个原则么?这不前后矛盾么?其实不矛盾。开放封闭原则是分情况讨论的。
changxin7
2019/09/10
3740
【Python基础之函数:多层语法糖、装饰器和装饰器修复技术及递归函数】
​ 多层语法糖是指在单个源代码函数名上方添加了多个语法糖,使这段源代码函数体具备多个功能
老虎也淘气
2024/01/30
2430
【Python基础之函数:多层语法糖、装饰器和装饰器修复技术及递归函数】
一文读懂Python装饰器由来(一)
Python装饰器是非常不错的特性,熟练掌握装饰器会让你的编程思路更加宽广,程序也更加pythonic。下面就让我们一起来探讨一下python的装饰器吧。
Python中文社区
2018/07/26
4960
python3装饰器
装饰器本质其实就是一个函数, 可以让其它函数不改动源代码的情况下增加其他新功能, 比如网站经常需要的权限校验等场景
py3study
2020/01/02
3470
python 装饰器
python 装饰器 描述 python 中一切皆对象,函数也可以当作参数传递 装饰器就是接受一个函数作为参数,添加功能后返回一个新函数的函数或类。 python 中使用 @ 来使用装饰器。(@ 只是装饰器的语法糖,可以等价替代为其他) 装饰器经常用到的功能就是在代码中添加 log 日志。 实例 下面简单编写一个记录函数耗时的装饰器。 使用函数编写一个装饰器 import time def log_time(func): # 接受一个函数作为参数 def _log(*args, **kwa
希希里之海
2019/05/15
5050
函数(三)
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。
py3study
2020/01/15
3360
python笔记35-装饰器
python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。 很多python初学者学到面向对象类和方法是一道大坎,那么python中的装饰器是你进入Python高级语法大门的一道坎。
上海-悠悠
2019/05/14
4770
python函数闭包-装饰器-03
callable() # 可调用的(这个东西加括号可以执行特定的功能,类和函数)
suwanbin
2019/09/26
5020
day20-python之装饰器
1.装饰器 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import time 4 def cal(l): 5 start_time=time.time() 6 res=0 7 for i in l: 8 time.sleep(0.1) 9 res+=i 10 stop_time = time.time() 11 print('函数的运行时间是%s' %(sto
py3study
2020/01/16
3240
Python函数详解二(闭包、装饰器)
闭包其实利用了函数嵌套的概念,一般函数在内部定义一个变量,在外部由于作用域的关系是调用不到的,而闭包是将变量包起来,不管在哪里都可以调用的到。
吾非同
2020/10/26
6210
day11-装饰器
  通常为了是代码更加优美,于是引入语法糖的概念。这里将对上述第二段代码进行改进,他们的作用和结果完全相同。
py3study
2020/01/15
3730
Python3 装饰器理解
谈装饰器之前,需明白一件事,Python 中的函数和 Java、C++ 不一样,Python 中的函数可以像普通变量一样当做参数传递给另外一个函数,代码示例如下:
嵌入式视觉
2022/09/05
2360
python利器-装饰器
说装饰器之前,先举一个生活的例子,比如秋天的时候,我们只穿一件夹克就可以保暖,但是到了冬天的时候,我想让这件夹克更加保暖一点,给夹克加点棉,到春天的时候,天气那么冷了,还想穿这件夹克,但是因为加了棉,会比较热,需要把棉去掉。但是这样显得比较麻烦,假如我们在不改变夹克的基础上,我们穿一件保暖衣服,天气热的时候就脱掉,让我们随时能够保暖也不至于太热,这个保暖衣服就有点相当于python的装饰器,python装饰器可以扩展原来函数的功能,并且不改变原来函数,用好装饰器,有时候能让我写代码事半功倍。
搁浅同学
2022/07/21
3210
面试题-python 什么是装饰器(decorator )?
python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。 很多python初学者学到面向对象类和方法是一道大坎,那么python中的装饰器是你进入Python高级语法大门的一道坎。
上海-悠悠
2021/03/19
3K1
相关推荐
闭包函数和装饰器
更多 >
LV.0
这个人很懒,什么都没有留下~
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档