文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

对Python中装饰器(Decorato

2023-01-31 02:36

关注

  有时候我们项目中的某些功能做些修改即需要对内部的某些函数添加一些附加功能,但是为了安全起见不想改变函数的源代码以及函数的调用方式,那么装饰器在这个地方会给我们带来很大的帮助。

  装饰器(Decorator):(又叫语法糖)

  定义:本质是函数,功能(装饰其它函数)就是为其他函数添加附加功能

  原则:(1).不能修改被装饰的函数的源代码

            (2).不能修改被装饰的函数的调用方式

1.先来实现一个简单的装饰器示例:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#定义一个简单的装饰器
def simple_wrapper(func):
    def wrapper():
        print("我是装饰器,我用来装饰%s" % func.__name__)
        func()
    return wrapper
#需要装饰的函数
@simple_wrapper
def say_hello():
    print("Hello World")
#执行say_hello()函数
say_hello()
'''运行结果如下:
我是装饰器,我用来装饰say_hello
Hello World
'''

  上边实现了一个简单的装饰器,能过用来装饰不带参数的函数,通过这个简单的示例,我们大概对装饰器的基本实现有一个大概的了解。但是如果想充分了解并掌握装饰的原理必要还要对python中的高阶函数、嵌套函数、以及函数即“变量”等概念有一定的了解和掌握。下边我会对装饰器以及相关的内容进行举例说明。

2.上边实现了一个简单的能够装饰不带参数的装饰器,但在正常情况下,我们的函数都需要传入适当的参数,如何能够实现对有参数的方法进行装饰呢?

#!/usr/bin/env python
# -*- coding:utf-8 -*-
def simple_wrapper(func):
    def wrapper(*args, **kwargs):
        print("我是装饰器,我用来装饰%s方法" % func.__name__)
        func(*args, **kwargs)
    return  wrapper
@simple_wrapper
def say_hello(name):
    print("Hello",name)
#执行say_hello()函数
say_hello("Jack")
'''运行结果:
我是装饰器,我用来装饰say_hello方法
Hello Jack
'''
#是不是同样很简单呢? 这种方式既可以装饰带任意参数的函数,也可以装饰不带参数的函数。

3.上边的装饰器已经可以实现基本要求,即可以完成对指定的函数添加附加功能的作用,但是在某些特定时候,我们需要装饰器自身也带上参数,如何实现呢?

#!/usr/bin/env python
# -*- coding:utf-8 -*-
def my_wrapper(args):
    print("我的参数是:",args)
    def simple_wrapper(func):
        def wrapper(*args, **kwargs):
            print("我是装饰器,我用来装饰%s方法" % func.__name__)
            func(*args, **kwargs)
        return  wrapper
    return simple_wrapper
    
@my_wrapper("simple")
def say_hello(name):
    print("Hello",name)
#执行say_hello()函数
say_hello("Jack")
'''运行结果:
我的参数是: simple
我是装饰器,我用来装饰say_hello方法
Hello Jack
'''

   是不是同样的很简单呢? 

   简单是简单,但是关键装饰器是怎么实现对其它函数添加附加功能呢?上边的函数是如何运行的呢?下面请看下边的简单示例:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
def simple_wrapper(func):
    def wrapper(*args, **kwargs):
        print("我是装饰器,我用来装饰%s方法" % func.__name__)
        func(*args, **kwargs)
    return  wrapper
    
def say_hello(name):
    print("Hello",name)
    
say_hello = simple_wrapper(say_hello)   #这里就等同于@simple_wrapper的作用
#其实这里相当于say_hello=wrapper
say_hello("Jack")        #所有在执行say_hello("Jack"),就相当调用了wrapper("Jack")函数

   简单解释:可以看到上边也能实现了装饰器的功能,对该示例简要分析:因为在python中函数作为一个对象但也可以看成一种“变量”,不仅可以将函数名拿来赋值给其它变量,也可以将函数名当做参数传递给其它函数,并且还可以将函数名作为返回值。(通俗点可以这样说,就是函数名在内存中就是一个内存地址,它指向函数体的内存地址空间,所以可以将函数名当做一个“变量”来进行相关操作,单当在函数名"变量"后边加上()的时候它就变成了函数调用,会去执行函数体。)在看上边的小例子,当执行say_hello = simple_wrapper(say_hello) 这一步的时候,将函数名say_hello当做参数传给了函数simple_wrapper(),但是接着函数simple_wrapper()将内部函数wrapper作为返回值返回,然后say_hello“被重新复制”,即say_hello指向了wrapper函数体的内存空间,接着当执行say_hello("Jack")的时候就相当于执行wrapper("Jack")。

4.通过上边的示例我们会发现当使用装饰器的时候,函数say_hello其实被simple_wrapper取代了,理所当然它的__name__等信息都变成了simple_wrapper函数的信息。如何既能让函数被装饰,又不改变其自身的信息呢?其实在Python里提供了一个functools.wraps,而wraps也是一个装饰器,它作用就是实现这种功能的。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
def simple_wrapper(func):
    def wrapper(*args, **kwargs):
        print("我是装饰器,我用来装饰%s方法" % func.__name__)
        func(*args, **kwargs)
    return  wrapper
@simple_wrapper
def say_hello(name):
    print("Hello",name)
#输出say_hello现在的__name___属性
print(say_hello.__name__)  #输出结果为:wrapper
'''
######使用functools.wraps
from functools import wraps
def simple_wrapper(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("我是装饰器,我用来装饰%s方法" % func.__name__)
        func(*args, **kwargs)
    return  wrapper
@simple_wrapper
def say_hello(name):
    print("Hello",name)
#输出say_hello现在的__name__属性
print(say_hello.__name__)  #输出结果为:say_hello

5.其实一个函数可以同时定义多个装饰器,当一个函数定义多个装饰器时,装饰器的执行顺序是先执行最里层的装饰器最后调用最外层的装饰器,简单示例:

@a
@b
@c
def say_hello():
   pass
#该示例中装饰器的执行顺序是c > b > c(等效于a(b(c(say_hello))))


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯