首页 > 编程语言 >Python中的装饰器

Python中的装饰器

时间:2023-12-01 11:23:46浏览次数:37  
标签:return 函数 Python decorator print 装饰 def

一、装饰器的作用

装饰器是Python中一种强大的编程工具,它允许我们在不修改原始函数代码的情况下,动态地增加功能或修改函数行为。装饰器提供了一种简洁而优雅的方式来修改、扩展或包装函数,使代码更具可读性和可维护性。

装饰器的主要作用包括:

  • 添加额外的功能或逻辑,如日志记录、性能分析、输入验证等。
  • 修改函数的行为,如缓存结果、重试机制等。
  • 分离关注点,将横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来。

二、装饰器的原理

在理解装饰器之前,我们需要了解一些Python的基础知识:函数是一等公民(first-class citizen),即函数可以被赋值给变量、作为参数传递和作为返回值返回。装饰器利用了这个特性。

装饰器本质上是一个函数,它接受一个函数作为参数,然后返回一个新的函数。这个新函数通常包装了原始函数,即在原始函数的前后添加了一些额外的代码或逻辑。通过将装饰器应用于函数,我们可以在不修改函数定义的情况下,动态地修改函数的行为。

三、装饰器的使用方法

例子1:日志记录

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Calling function: {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@log_decorator
def add(a, b): 	# 被装饰的函数
    return a + b

result = add(2, 3)  # 输出:Calling function: add
print(result)  # 输出:5

在上述例子中,log_decorator是一个装饰器函数,它接受一个函数作为参数,并返回一个新的函数 wrapper。在 wrapper函数中,我们可以在调用原始函数之前或之后添加额外的代码。通过将装饰器应用于 add函数,我们实现了在调用 add函数时打印函数名的功能。

你可能认为,如果不用装饰器,实现这个功能也不难,比如:

def add(a, b):
    print(f"Calling function: add")
    return a + b

result = add(2, 3)
print(result)

然而,这只是一个函数,如果有多个函数都需要被加入这个功能,那修改起来就很麻烦,如果使用装饰器,就很容易,例如:

@log_decorator
def minus(a, b): # 被装饰的函数
    return a - b

@log_decorator
def multiply(a, b): # 被装饰的函数
    return a * b

@log_decorator
def devide(a, b): # 被装饰的函数
    return a / b

这样,在不改动原函数的情况下,所有函数都实现了记录日志的功能。下面再看一个更复杂的例子。

例子2:性能分析

import time

def performance_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"运行时间 {func.__name__}: {end_time - start_time} 秒")
        return result
    return wrapper

@performance_decorator
def f():
    time.sleep(2.5)

result = f()  # 输出:运行时间 f: 2.500232219696045 秒


@performance_decorator
def g(): # 被装饰的函数
    time.sleep(3.3)

result = g()  # 输出:运行时间 g: 3.301257610321045 秒

在上述例子中,performance_decorator是一个装饰器函数,它用来计算函数的执行时间。通过将装饰器应用于其它函数,我们可以方便地测量函数的执行时间。fg 函数并没有实际内容,只是用 sleep 来模拟运行时间。对于每个函数,都输出了正确的测量结果。对于更多的函数,也可以用这个装饰器来完成。

例子3. 带参数的装饰器

当装饰器有参数时,通常需要定义一个外层函数来接收参数,并在外层函数内再定义一个真正的装饰器函数。以下是一个有参数的装饰器案例,用于限制函数执行的次数:

def limit_execution_times(max_executions):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if wrapper.execution_count < max_executions:
                result = func(*args, **kwargs)
                wrapper.execution_count += 1
                return result
            else:
                print(f"函数 '{func.__name__}' 已达到最大执行次数.")
                return None

        wrapper.execution_count = 0
        return wrapper
    return decorator

# 使用装饰器限制函数最多执行3次
@limit_execution_times(3)
def print_hello(): # 被装饰的函数
    print("Hello, world!")

print_hello()  # 输出:Hello, world!
print_hello()  # 输出:Hello, world!
print_hello()  # 输出:Hello, world!
print_hello()  # 输出:函数 'print_hello' 已达到最大执行次数.

在这个例子中,我们定义了一个带参数的装饰器 limit_execution_times,它接收一个参数 max_executions,表示函数的最大执行次数。在装饰器内部,我们使用一个内部函数 wrapper来包装原始函数,同时添加了一个 execution_count属性来记录函数执行的次数。每次调用被装饰的函数时,都会检查执行次数是否超过最大执行次数,如果未超过,则继续执行原始函数;如果已达到最大执行次数,则输出相应提示信息,并不再执行原始函数。这样,我们就实现了一个带参数的装饰器,用于限制函数的执行次数。

四、装饰器的使用场合

装饰器在很多场景下都可以发挥作用,例如:

  • 记录日志或统计日志;
  • 对函数进行输入验证或参数校验;
  • 实现缓存机制,避免重复计算;
  • 实现权限控制或身份验证;
  • 实现性能分析或调试;
  • 实现事务处理或错误处理等。

装饰器可以帮助我们将这些横切关注点从核心业务逻辑中分离出来,提高代码的可读性、可维护性和复用性。

标签:return,函数,Python,decorator,print,装饰,def
From: https://www.cnblogs.com/Aniiwuyan/p/17869302.html

相关文章

  • python装饰器
    装饰器本质上是一个Python函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象Python中的函数可以像普通变量一样当做参数传递给另外一个函数,也可以把一个函数作为返回值,这类函数被称为高阶(Higher-order)函数它经常......
  • python HTTP Server 文件上传与下载
    pythonHTTPServer文件上传与下载实现在局域网(同一WIFI下)文件上传与下载该模块通过实现标准GET在BaseHTTPServer上构建和HEAD请求。(将所有代码粘贴到同一个py文件中,即可使用)所需包基于python3版本实现,python2版本无涉猎importosimportsysimportargparseimport......
  • python装饰器
    importtimedefwrapper(type):print('start------',type)defoutter(fun):definner(*args,**kwargs):start_time=time.time()fun(*args,**kwargs)end_time=time.time()print('ru......
  • python助手
    python助手AssumetheroleofPyAssist,ahighlyskilledAIassistantspecializinginPythonprogramming.AsanexpertinthePythonlanguageanditsecosystem,yourmissionistoprovideguidance,support,andvaluableinsightstousersseekinghelpwithP......
  • 【Python】十六进制、八进制、二进制的写法
    1、十六进制语法:0x开头a=0x1122、八进制语法:0o开头a=0o1123、二进制语法:0b开头a=0b112......
  • 如何在 Python 中做到类似 #ifdef DEBUG
    类似#ifndefNDEBUGdo_something(...)#elsedo_otherthing(...)#endiflogging模块如果有无NDEBUG,只在于是否输出一些信息,那么可以使用logging模块,这是一个用于记录和管理日志信息的标准库,通过配置日志级别,可以控制不同等级的日志的输出。importlogginglogging.basic......
  • 【Python】函数参数
    1、参数默认值语法:deffun(arg1=value,arg2=value):pass有默认值的参数必需放在末尾。2、可变参数语法:deffun(*args):pass可变参数必需放在末尾。args在函数内部是一个元组。3、关键字参数语法:deffun(**args):pass关键字参数必需放在末尾,args在函......
  • Python基础之程序与用户交互
    【一】Python基础之程序与用户交互【一】程序如何与用户交互用户通过input命令在窗口内与输入就可以让用户和窗口进行交流input接受的所有数据类型都是str类型username=input("请输入你的用户名:")passwd=input("请输入你的密码:")print(type(username))print(type(......
  • 【Python】【OpenCV】轮廓检测
    Code:1importcv22importnumpyasnp34img=np.zeros((200,200),dtype=np.uint8)5img[50:150,50:150]=25567#ret,thresh=cv2.threshold(img,127,255,0)8contours,hierarchy=cv2.findContours(img,cv2.RETR_TREE,cv2.CHAIN_APPROX......
  • Python 内置方法
    【一】整型1.1-十进制转二进制bin()num=20print(bin(num))#0b101001.2-十进制转八进制oct()num=30print(oct(num))#0o361.3-十进制转十六进制hex()num=40print(hex(num))#0x281.4-非进制转十进制:int()hex1=0x28print(int(hex1))......