iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python装饰器相关知识点
  • 611
分享到

python装饰器相关知识点

2023-06-29 09:06:11 611人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

小编给大家分享一下python装饰器相关知识点,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、装饰器1.相关知识点*args:负责将多余的位置实参汇总,赋值给a

小编给大家分享一下python装饰器相关知识点,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

一、装饰器

1.相关知识点

  • *args:负责将多余的位置实参汇总,赋值给args

  • **kwargs:负责将多余的关键字实参汇总,赋值给kwargs

命名空间与作用域

函数对象:

  • 可以把函数当成参数传入

  • 可以把函数当做返回值返回

函数的嵌套定义:在函数内定义函数

闭包函数:父函数的返回值为一个函数,被返回的函数调用了父函数的局部变量,且该函数可以在父函数外部执行

装饰器:

装饰器:定义一个为其他函数添加功能的函数

为什么要使用装饰器?

  • 开放封闭原则:开放扩展功能但封闭源代码的修改

  • 装饰器就是在不修改装饰对象源代码以及调用方式的前提下,为装饰对象添加新功能

装饰器实现:

需求:不修改源代码,计算代码执行时间

 源代码:

import timedef func0(x):    time.sleep(1)    print(x)func0(0)# 方案一:实现了计算代码执行时间的功能,但修改了源代码,不符合要求def func1(x):    start = time.time()    time.sleep(1)    print(x)    end = time.time()    print('方案一 运行时间:{}'.fORMat(end - start))func1(1)# 方案二:满足要求,但代码不具备重用性start = time.time()func0(2)end = time.time()print('方案二 运行时间:{}'.format(end - start))# 方案三:将方案二封装为函数,但修改了函数的调用方式,不符合要求def wrapper():    start = time.time()    func0(3)    end = time.time()    print('方案三 运行时间:{}'.format(end - start))wrapper()# 方案四:不修改原函数的调用方式def wrapper(x):    start = time.time()    func0(x)    end = time.time()    print('方案四 运行时间:{}'.format(end - start))wrapper(4)# 方案五:方案四参数被写死,优化方案四def wrapper(*args, **kwargs):    start = time.time()    func0(*args, **kwargs)    end = time.time()    print('方案五 运行时间:{}'.format(end - start))wrapper(5)# 方案六:方案五函数被写死,优化方案五,但修改了源代码的调用方式def outter(a):    def wrapper(*args, **kwargs):        start = time.time()        a(*args, **kwargs)        end = time.time()        print('方案六 运行时间:{}'.format(end - start))    return wrapperf = outter(func0)f(6)# 方案七:优化方案六(outter即为装饰器,用于装饰func0)def outter(a):    def wrapper(*args, **kwargs):        start = time.time()        a(*args, **kwargs)        end = time.time()        print('方案七 运行时间:{}'.format(end - start))    return wrapperfunc0 = outter(func0)    # 偷梁换柱,调用者无感知func0(7)

运行结果:

0
1
方案一 运行时间:1.001857042312622
2
方案二 运行时间:1.0040733814239502
3
方案三 运行时间:1.0017154216766357
4
方案四 运行时间:1.007995367050171
5
方案五 运行时间:1.0145602226257324
6
方案六 运行时间:1.0046615600585938
7
方案七 运行时间:1.0094060897827148

2.语法糖

  • 使用语法糖,需要将装饰器放到被装饰对象前

# 不使用语法糖import timedef func0(x):    time.sleep(1)    print(x)# func0(0)def outter(a):    def wrapper(*args, **kwargs):        start = time.time()        a(*args, **kwargs)        end = time.time()        print('运行时间:{}'.format(end - start))    return wrapperfunc0 = outter(func0)func0('hello')# 使用语法糖import timedef outter(a):    def wrapper(*args, **kwargs):        start = time.time()        a(*args, **kwargs)        end = time.time()        print('运行时间:{}'.format(end - start))    return wrapper@outter # 语法糖,等价于该行func0 = outter(func0)def func0(x):    time.sleep(1)    print(x)func0('hello')print(func0.__name__)

运行结果:

hello
运行时间:1.0050427913665771
wrapper

3.装饰器模板

 # 装饰器模板 def decorator_name(x):     def wrapper(*args, **kwargs):         # ...新添加的功能...         # 下为调用原函数的格式         x(*args, **kwargs)     return wrapper@decorator_name def func_name():     pass

扩展:真正实现偷梁换柱,调用者无感知

  • 不使用装饰器

 # 不使用装饰器import timedef func0(x):    time.sleep(1)    print(x)func0('hello')print(func0.__name__) # 查看函数名 print(help(func0)) # 查看帮助信息(主要为注释内容)

运行结果:

hello
func0
Help on function func0 in module main:

func0(x)
这是函数

None

使用装饰器:

import timedef outter(a):    def wrapper(*args, **kwargs):        '''这是装饰器'''        start = time.time()        a(*args, **kwargs)        end = time.time()        print('运行时间:{}'.format(end - start))    return wrapper@outter # func0 = outter(func0)def func0(x):    '''这是函数'''    time.sleep(1)    print(x)func0('hello')print(func0.__name__)print(help(func0))

运行结果:

hello
运行时间:1.011878490447998
wrapper
Help on function wrapper in module main:

wrapper(*args, **kwargs)
这是装饰器

None

呕吼,露馅了

  • 解决方法,将原函数的属性和方法,赋值给装饰器内的wrapper

import timedef outter(a):    def wrapper(*args, **kwargs):        '''这是装饰器'''        start = time.time()        a(*args, **kwargs)        end = time.time()        print('运行时间:{}'.format(end - start))    wrapper.__name__ = a.__name__    wrapper.__doc__ = a.__doc__    return wrapper@outter # func0 = outter(func0)def func0(x):    '''这是函数'''    time.sleep(1)    print(x)func0('hello')print(func0.__name__)print(help(func0))

运行结果:

hello
运行时间:1.0030155181884766
func0
Help on function func0 in module main:

func0(*args, **kwargs)
这是函数

None

但是,函数有很多属性和方法,一个一个手动修改过于麻烦,甚至可能会遗漏,但Python也提供了解决方法

import timefrom functools import wrapsdef outter(a):    @wraps(a)    def wrapper(*args, **kwargs):        '''这是装饰器'''        start = time.time()        a(*args, **kwargs)        end = time.time()        print('运行时间:{}'.format(end - start))    # wrapper.__name__ = a.__name__    # wrapper.__doc__ = a.__doc__    return wrapper@outter # func0 = outter(func0)def func0(x):    '''这是函数'''    time.sleep(1)    print(x)func0('hello')print(func0.__name__)print(help(func0))

运行结果:

hello
运行时间:1.0114128589630127
func0
Help on function func0 in module main:

func0(x)
这是函数

None

4.有参装饰器

  • 装饰器内需要传入参数,但是由于语法糖的限制,装饰器只能有一个参数,并且该参数仅用来接收被装饰对象的内存地址,如何传入其他参数?

  • 解决思路:将装饰器做成闭包函数

def outter(db_type):    # 装饰器auth    def auth(x):        def wrapper(*args, **kwargs):            if db_type == 'file':                name = input('请输入姓名:')                passwd = input('请输入密码:')                if name == 'zhangsan' and passwd == '123':                    x(*args, **kwargs)                    print('基于文件认证')                else:                    print('用户名或密码错误,认证失败')            elif db_type == 'mysql':                x(*args, **kwargs)                print('基于数据库认证')            else:                print('未知认证方式,不支持')        return wrapper    return auth# 函数auth = outter(db_type='file')@authdef file():    print('hello')auth = outter(db_type='Mysql')@authdef mysql():    print('world')msg = input('请选择认证方式(1=file|2=mysql):').strip()if msg =='1':    file()elif msg == '2':    mysql()else:    print('不支持')
  • 将传入的参数写入语法糖

def outter(db_type):    # 装饰器auth    def auth(x):        def wrapper(*args, **kwargs):            if db_type == 'file':                name = input('请输入姓名:')                passwd = input('请输入密码:')                if name == 'zhangsan' and passwd == '123':                    x(*args, **kwargs)                    print('基于文件认证')                else:                    print('用户名或密码错误,认证失败')            elif db_type == 'mysql':                x(*args, **kwargs)                print('基于数据库认证')            else:                print('未知认证方式,不支持')        return wrapper    return auth# 函数# auth = outter(db_type='file')# @auth@outter(db_type='file')def file():    print('hello')# auth = outter(db_type='mysql')# @auth@outter(db_type='mysql')def mysql():    print('world')msg = input('请选择认证方式(1=file|2=mysql):').strip()if msg =='1':    file()elif msg == '2':    mysql()else:    print('不支持')
  • 模板

# 有参装饰器模板def out_decorator_name(x,y,z):    def decorator_name(a):        def wrapper(*args, **kwargs):            # ...新添加的功能...            # 下为调用原函数的格式            a(*args, **kwargs)        return wrapper    return decorator_name@out_decorator_name(x,y,z=1)def func_name():     pass

以上是“python装饰器相关知识点”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网Python频道!

--结束END--

本文标题: python装饰器相关知识点

本文链接: https://www.lsjlt.com/news/323776.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作