iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >深入了解python装饰器
  • 706
分享到

深入了解python装饰器

2024-04-02 19:04:59 706人浏览 泡泡鱼

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

摘要

目录一、装饰器1.相关知识点2.语法糖3.装饰器模板4.有参装饰器一、装饰器 1.相关知识点 *args:负责将多余的位置实参汇总,赋值给args**kwargs:负责将多余的关键字

一、装饰器

1.相关知识点

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

命名空间与作用域

函数对象:

  • 可以把函数当成参数传入
  • 可以把函数当做返回值返回

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

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

装饰器:

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

为什么要使用装饰器?

  • 开放封闭原则:开放扩展功能但封闭源代码的修改
  • 装饰器就是在不修改装饰对象源代码以及调用方式的前提下,为装饰对象添加新功能

装饰器实现:

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

 源代码:

import time
def 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 wrapper
f = 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 wrapper
func0 = 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 time
def 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 wrapper
func0 = outter(func0)
func0('hello')

# 使用语法糖
import time

def 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 time


def 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 time

def 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 time

def 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 time
from functools import wraps

def 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')
@auth
def file():
    print('hello')


auth = outter(db_type='mysql')
@auth
def 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/141001.html(转载时请注明来源链接)

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

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

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

下载Word文档
猜你喜欢
  • 深入了解python装饰器
    目录一、装饰器1.相关知识点2.语法糖3.装饰器模板4.有参装饰器一、装饰器 1.相关知识点 *args:负责将多余的位置实参汇总,赋值给args**kwargs:负责将多余的关键字...
    99+
    2024-04-02
  • Java装饰者模式的深入了解
    目录一、装饰模式的定义和特点二、装饰模式的结构三、咖啡点单案例演示代码实例:四、总结总结一、装饰模式的定义和特点 在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些...
    99+
    2024-04-02
  • Python深入分析@property装饰器的应用
    目录什么是propertyproperty属性定义的两种方式@property属性值的限制什么是property 简单地说就是一个类里面的方法一旦被@property装饰,就可以像调...
    99+
    2024-04-02
  • 深入浅析Java中的装饰器
    深入浅析Java中的装饰器?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。定义:动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方...
    99+
    2023-05-31
    java 装饰器 ava
  • python闭包和装饰器你了解吗
    目录一、闭包1. 什么是闭包?2. 形成闭包的三个条件(缺一不可)3. 闭包的原理4. 闭包的好处二、装饰器1. 什么是装饰器2. 装饰器有什么用3. 小 练 习三. 编写...
    99+
    2024-04-02
  • python装饰器1:函数装饰器详解
    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 先混个眼熟 谁可以作为装饰器(可以将谁编写成装饰器): 函数 方法 实现了__call__的可调用类 装饰器可以去装饰谁(谁可以被装饰): 函数 方法 类 基础...
    99+
    2023-01-30
    详解 函数 python
  • python自动化测试中装饰器@ddt与@data源码深入解析
    目录一、使用ddt和data装饰器的大致框架如下,每个test_开头的方法,代表一条测试用例二、给类动态的增加方法案例1案例2:案例3:三、ddt和data的源码解析原因:解决:分部...
    99+
    2022-12-10
    python装饰器@ddt和@data python 自动化测试 python @ddt和@data源码
  • python装饰器详解
            python中的装饰器(decorator)一般采用语法糖的形式,是一种语法格式。比如:@classmethod,@staticmethod,@property,@xxx.setter,@wraps(),@func_na...
    99+
    2023-09-01
    python
  • python 装饰器理解
    在理解装饰器之前,先应该对闭包有个概念:所谓闭包,就是将组成函数的语句和这些语句的执行环境打包在一起时得到的对象,它的主要作用是封存上下文。这一特性可以巧妙的被用于现有函数的包装,从而为现有函数添加功能,这就是装饰器。装饰器的本质与作用装饰...
    99+
    2023-01-31
    python
  • 深入了解Python--元组
              ...
    99+
    2023-01-30
    Python
  • python装饰器2:类装饰器
    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 本文是装饰器相关内容的第二篇,关于类装饰器。 "类装饰器"有两种解读方式:用来装饰类的装饰器;类作为装饰器装饰其它东西。你如何认为取决于你,两种说法都有出现在其它的文章中。我的...
    99+
    2023-01-30
    python
  • 深入了解Python的继承
    目录面向对象三大特性:1、单继承1.1 继承的概念、语法和特点1)、继承的语法2)、专业术语总结面向对象三大特性: 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的...
    99+
    2024-04-02
  • 理解Python装饰器(一)
    python装饰器 装饰器是什么?我也不知道该如何给装饰器下定义。 1. 装饰器是函数,因为从代码的层面上来说,它就是开发人员定义的一个函数而已; 2. 装饰器就像是类的继承一样,通过装饰符,来实现函数与函数、函数与类之间的"继承" 3. ...
    99+
    2023-01-31
    Python
  • 深入理解Java设计模式之装饰模式
    目录一、前言二、什么是装饰模式1.定义:2.意图3.别名4.动机5.作用6.问题三、装饰模式的结构四、装饰模式的使用场景五、装饰模式的优缺点六、装饰模式的实现七、装饰模式的.NET应...
    99+
    2024-04-02
  • python装饰器
    什么是装饰器:   装饰器就是python中的一个语法糖。作用就是在不改动之前代码的情况下给某个函数增加相应想要增加的功能。 假设需求:   我在几个函数内分别放了一部电影,代码如下: 1 def mv1(): 2 print(...
    99+
    2023-01-30
    python
  • python-装饰器
    装饰器简介:给被装饰的函数在不更改代码的基础上增加新的功能;多个装饰器的执行顺序:从最靠近原始函数的装饰器开始执行,最后执行原始函数; 直接上个简单的例子就懂了: 一 最简单的装饰器:#!/usr/bin/python def deco(f...
    99+
    2023-01-31
    python
  • python 装饰器
    装饰器本质上是一个Python函数,它可以让其他函数在不雲要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面雲求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳...
    99+
    2023-01-30
    python
  • Python学习之装饰器与类的装饰器详解
    目录装饰器装饰器的定义装饰器的用法类中的装饰器类的装饰器 - classmethod类的装饰器 - staticmethod类的装饰器 - property通过学习装饰器可以让我们更...
    99+
    2024-04-02
  • Python的闭包和装饰器你真的了解吗
    目录闭包装饰器总结闭包 闭包就是能够读取其他函数内部变量的函数。 def test1(k, b): def test1_1(x): print(k*x+b) ...
    99+
    2024-04-02
  • python 装饰器案例解析
    本文介绍几个装饰器案例,来分析装饰器是如何调用的获取函数运行时间的例子写装饰器,不可以一步到位,要慢慢一点一点的来先写好2个函数import time def test1():    &nb...
    99+
    2023-01-30
    案例 python
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作