python:装饰器【精】

本文围绕Python装饰器展开,介绍其本质是返回函数的函数,可在不改变原函数代码基础上增加功能。通过多个示例,如比较函数运行时间、调用函数返回值、处理装饰器参数及使用多个装饰器等,展示了装饰器的具体应用和实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

装饰器:

把函数当作参数,返回一个替代版的函数
本质为返回函数的函数


作用:

##在不改变原函数【代码】的基础上,给函数增加功能

示例:

import time   ##导入时间模块

def decorator(func):  ##装饰器
    def wrapper(*args,**kwargs):
        print(time.time())    ##打印时间
        func(*args,**kwargs)  ##执行原函数
    return wrapper  ##使wrapper函数执行


@decorator  ##声明有装饰器
def f1():    ##原函数
	print('This is a function')

f1()

运行结果:
在这里插入图片描述
在调用原函数后,会先执行装饰器decorator函数,进入装饰器后通过返回值wrapper再执行wrapper函数,打印时间,执行原函数。装饰器是通过把原函数当作参数,通过形参-实参使用的。


【帮助文档写法】【添加装饰器比较两个函数运行时间】:

比较两个连接函数的运行时间【添加装饰器比较】【帮助文档写法】

import random   ##导入随机序列
import string   ##导入字符
import functools  ## functools模块中主要包含了一些函数装饰器和便捷的功能函数
import time     ##导入时间

li = [random.choice(string.ascii_letters) for i in range(10)]     ##随机选择100个字符

def timec(fun):    ##装饰器
    @functools.wraps(fun)   ##可以保证装饰器不会对被装饰函数造成影响
    def wrapper(*args,**kwargs): ##wrapper函数 ##args:元组 kwargs:字典
        start_time = time.time()   ##开始时间
        res = fun(*args,**kwargs) ##运行原函数,并保留结果到res中
        end_time = time.time()     ##结束时间
        print('运行时间为: %.6f' %(end_time - start_time))  ##打印运行时间
        return res  ##返回值
    return wrapper  ##进入函数后执行wrapper的指定

@timec
def con_add():   ##生成序列的方法一
    """这是一个con_add函数"""   ##说明
    s = ''
    for i in li:
        s += (i + ',')
    print(s)

@timec
def join_add():    ##生成序列的方法二
    print(','.join(li))

con_add()   ##执行方法一
join_add()  ##执行方法二

##指定函数的帮助文档,函数名的获取【默认获取的是最先的装饰器的文档和名字】

print(con_add.__doc__)   ##打印con_add函数中的说明:"""这是一个con_add函数"""
print(con_add.__name__)  ##打印con_add函数的名字:con_add

运行结果:

在这里插入图片描述

在上面这个例子中,充分运用了装饰器,使得在不更改原代码的基础上增加了功能。但是对于装饰器中的函数返回值并没有使用。
下面再举一例说明:

【装饰器中函数返回值调用】:

还是查看时间,这次查看一个函数的运行时间

import functools
import time

def add_log(fun):  #装饰器
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):  #wrapper函数
        start_time = time.time()  #开始时间
        res = fun(*args,**kwargs) #运行原函数,并保留其结果到res
        end_time = time.time()    #结束时间
        print('[%s] 函数名: %s, 运行时间: %.6f, 运行返回值结果: %d'
              %(time.ctime(),fun.__name__,end_time - start_time,res))
        return res  ##返回值为res
    return wrapper

@add_log
def add(x,y):
    time.sleep(1)
    return x + y

add(5,2)

图示:

在这里插入图片描述
通过装饰器中的函数返回值,来得到函数运行的结果,并输出。


【装饰器中有参数时:双层装饰器达到传递参数功能】:

import time
import functools

def log_kind(kind):    #外层装饰器
    def add_log(fun):   #内层装饰器
        @functools.wraps(fun)    #保证装饰器不会对原函数的一些模块造成影响
        def wrapper(*args,**kwargs):  #装饰器中执行功能的函数
            start_time = time.time()  #开始时间
            res = fun(*args,**kwargs)  #将函数运行结果赋值给res
            end_time = time.time()    #结束时间
            print('<%s>[%s] 函数名: %s, 运行时间: %.6f, 运行返回值结果: %d'
                  %(kind,time.ctime(),fun.__name__,end_time - start_time,res))  #打印内容
            return res  #将函数运行结果返回   #这里可以不写,并没有调用该wrapper函数的返回值
        return wrapper  #使调用wrapper函数
    return add_log      #使调用add_log函数

@log_kind('debug')  #添加装饰器
def add(x,y):   #原函数:1秒钟后返回一个加法结果,但是没有输出
    time.sleep(1)
    return x + y  #

add(1,2)  #运行原函数

运行结果:
在这里插入图片描述
这个例子中,我们主要是要观察lod_kind()装饰器中,我们使用时给其中添加了参数’debug’,而在通常使用的装饰器中是没有添加参数的。那么我们使用多层装饰器来达到传递参数的功能。【装饰器的()中要加入被执行的函数,所以无法直接加入参数】


【多个装饰器】:

def decorator_a(fun):    #装饰器一
    def inner_a(*args,**kwargs):   #装饰器内执行动作的函数
        print('Get in inner_a')    #打印内容
        return fun(*args,**kwargs)   #执行原函数,装饰器返回其值
    return inner_a  #使inner_a函数被执行

def decorator_b(fun):    #装饰器二
    def inner_b(*args,**kwargs):  #装饰器内执行动作的函数
        print('Get in inner_b')   #打印内容
        return fun(*args,**kwargs)  #执行原函数,装饰器返回其值
    return inner_b   #使inner_b函数被执行

@decorator_b    #添加装饰器b
@decorator_a    #添加装饰器a
def f(x):     #原函数
    print('Get in f')  #打印内容
    return x*2   #返回两个参数x

f(1)  #执行原函数

运行结果:
先添加了装饰器b,则先打印出了装饰器b的结果。 上述代码中的各返回值都没有去调用,可以省略。
在这里插入图片描述


                      大大的小小阳
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值