Python装饰器实现方法及应用场景详解

Python装饰器实现方法及应用场景详解

1. 概述

装饰器是 Python 中非常重要的概念,几乎所有 Python 框架都大量使用到了装饰器。它可以用于功能增强、日志处理、输入验证和安全控制等场景。

装饰器本质上是一个 Python 函数或类,并在不改变原函数/方法定义的基础上对其进行增强。Python 中借助函数式编程的特点,可以很方便地实现装饰器。

2. Python装饰器实现方法

装饰器可以使用函数或类实现,下面分别介绍。

2.1 函数实现装饰器

函数装饰器包装器的通用格式如下所示:

def decorator(func):
    def wrapper(*args, **kwargs):
        # 在调用原函数前进行增强操作
        res = func(*args, **kwargs)
        # 在调用原函数后进行增强操作
        return res
    return wrapper

将被装饰的函数作为参数传给装饰器函数,返回一个新的经过增强的函数并替换掉原函数。

wrapper 函数中,可以在调用原函数前后进行额外的逻辑处理。

例如,下面的代码实现了一个简单的计算程序,加入了装饰器对输入的检查功能,如果输入值为负数则自动转换成正数:

def check_input(func):
    def wrapper(*args, **kwargs):
        for arg in args:
            if arg < 0:
                print(f"Warning: Invalid input value ({arg}), automatically converts it to positive value.")
                arg = -arg
        return func(*args, **kwargs)
    return wrapper

@check_input
def add(x, y):
    return x + y

print(add(1, -2)) # 输出:Warning: Invalid input value (-2), automatically converts it to positive value.
                  #      -1

在上面的代码中,add 函数被 check_input 装饰器装饰,该装饰器会检查传入参数的值是否为负数,若是则转化为相应正数,然后才调用 add 函数,返回结果。

2.2 类实现装饰器

类装饰器的实现方式类似于函数装饰器。一个类装饰器通常具有 __call__ 方法,且能够接受被装饰的方法或函数作为参数,并在其上执行增强操作。

class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        # 在调用原函数前进行增强操作
        res = self.func(*args, **kwargs)
        # 在调用原函数后进行增强操作
        return res

实现后,我们可以使用装饰器类对函数进行装饰。

例如,下面的代码实现了一个简单的装饰器类,该装饰器类在调用被装饰的函数前后打印一行信息:

class Logger:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f"Call {self.func.__name__} function...")
        res = self.func(*args, **kwargs)
        print(f"{self.func.__name__} function finished.")
        return res

@Logger
def foo(x, y):
    return x + y

print(foo(1, 2)) # 输出:Call foo function...
                 #      foo function finished.
                 #      3

在上面的代码中,foo 函数被 Logger 装饰器装饰,该装饰器会在调用 foo 函数前后打印一行信息,然后才调用 foo 函数,返回结果。

3. 装饰器应用场景

3.1 功能增强

装饰器可以对函数进行增强。例如,在框架中处理请求/响应对象时,可以使用装饰器简化代码复杂度。

例如,下面的代码实现了一个装饰器类,对 Flask 框架中的请求进行记录:

def record_request(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"Request URL: {request.url}")
        print(f"Request IP Address: {request.remote_addr}")
        print(f"Request Method: {request.method}")
        print(f"Request Time: {end - start:.3f}s")
        return res
    return wrapper

@app.route("/")
@record_request
def hello():
    return "Hello World!"

在上面的代码中,record_request 装饰器类会在调用 hello 函数前后记录请求 URL、IP地址、请求方法和请求时间。

Flask 能够接收来自浏览器或其他客户端的HTTP请求,它内置了多个数据结构来处理请求,其中重要的一点就是当前请求的信息都在一个名为request的全局变量里,可以通过 Flask 的request模块来使用。

3.2 输入验证

装饰器可以对函数的输入参数类型进行检查。例如,在 Web 开发中需要对输入内容进行验证,以保证数据的有效性和安全性。

例如,下面的代码实现了一个装饰器函数,对输入的数值范围进行检查。

def check_range(min_val, max_val):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for arg in args:
                if arg < min_val or arg > max_val:
                    raise ValueError(f"Invalid value for parameter ({arg}), should between ({min_val}, {max_val}).")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@check_range(min_val=0, max_val=100)
def square(x):
    return x * x

print(square(3))
print(square(-1)) # 抛出异常:ValueError: Invalid value for parameter (-1), should between (0, 100).

在上面的代码中,check_range 装饰器函数会检查函数输入的参数值是否在指定的范围内,如果不在所指定的范围内,则抛出异常(ValueError),提示用户输入有误。

3.3 输出记录

装饰器可以对函数的输出结果进行记录。例如,记录函数的返回结果,方便后续分析和调试。

下面是一个简单示例程序,演示对函数输出记录的实现:

def log_result(func):
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print(f"Function {func.__name__} returned: {res}")
        return res
    return wrapper

@log_result
def add(x, y):
    return x + y

add(1, 2) # 输出:Function add returned: 3

在上面的程序中, add 函数被 log_result 装饰器装饰,该装饰器会在调用完 add 函数后,记录函数的返回结果。

4. 总结

装饰器是 Python 中应用广泛的编程语法,在函数功能扩展、输入输出检查、日志记录等场景中都有广泛应用。只要掌握装饰器的实现方式和应用场景,就能有效提升 Python 中程序开发的效率和质量。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python装饰器实现方法及应用场景详解 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • python实现提取百度搜索结果的方法

    下面是“python实现提取百度搜索结果的方法”的完整攻略。 1. 确定用到的库和工具 首先需要导入一些库和工具,来实现提取百度搜索结果的操作。这些库和工具包括: requests:用于发送HTTP请求 BeautifulSoup:用于解析HTML代码 lxml:解析器,用于解析HTML代码 2. 爬取搜索结果页面 通过requests发送HTTP GET请…

    python 2023年5月14日
    00
  • Python函数的嵌套详解

    Python函数的嵌套详解 Python函数的嵌套是指在一个函数体内定义另外一个函数,被定义的函数可以被外部函数调用,也可以被内部函数调用。在Python中,函数嵌套是一种很常见的技巧,可以使我们的代码更加清晰易读,提高代码的复用性。本文将详细介绍Python函数的嵌套。 基本语法 Python函数的嵌套语法如下所示: def outer_function(…

    python 2023年6月6日
    00
  • 详解python 破解网站反爬虫的两种简单方法

    详解python 破解网站反爬虫的两种简单方法 简介 在爬取网站数据的过程中,经常会遇到网站反爬虫的情况,例如:IP封禁、UA检测、验证码等。本文将讨论两种简单的python破解网站反爬虫的方法。 方法一:伪装UA 部分网站反爬虫机制是检测爬虫的User-Agent,所以我们可以用伪装的方式进行欺骗。 示例代码: import requests url = …

    python 2023年5月14日
    00
  • Python小工具之消耗系统指定大小内存的方法

    当我们需要测试 Python 程序的性能时,可以通过消耗系统指定大小的内存来模拟处理大数据的场景,并测试程序的稳定性和性能。本文将详细讲解 Python 小工具之消耗系统指定大小内存的方法,具体如下: 1. 通过分配大量字符串来消耗内存 可以通过分配大量的字符串来消耗系统指定大小内存。以下是示例代码: def consume_memory(size): &q…

    python 2023年6月3日
    00
  • python数据爬下来保存的位置

    在Python中,我们可以使用各种库和工具来爬取数据,如Requests、BeautifulSoup、Scrapy等。在爬取数据后,我们通常需要将数据保存到本地文件中,以便后续处理和分析。本文将介绍Python数据爬下来保存的位置的完整攻略,包括保存到文本文件、CSV文件和数据库中的方法,以及两个示例说明。 保存到文本文件 在Python中,我们可以使用op…

    python 2023年5月14日
    00
  • python抓取网站的图片并下载到本地的方法

    让我来详细讲解一下“Python抓取网站的图片并下载到本地的方法”的完整攻略。 步骤一:导入依赖库 我们需要导入requests、os和re三个依赖库,确保能够正常进行HTTP请求、保存图片文件和正则匹配字符串: import requests import os import re 步骤二:定位图片链接 将要抓取的图片所在的页面URL,使用requests…

    python 2023年6月3日
    00
  • Python随手笔记第一篇(2)之初识列表和元组

    Python随手笔记第一篇(2)之初识列表和元组 在Python中,列表和元组是两种常用的数据类型。本攻略将详细介绍列表和元组,包括它们的定义、创建访问、修改等操作。 列表 列表是Python中最常用的数据类型之一,是一种有序的可变序列,可以包任意类型的元素。以下是Python列表的定义和创建方式: # 定义空列表 my_list = [] # 定义一个包含…

    python 2023年5月13日
    00
  • Python线程之定位与销毁的实现

    一、定义线程 Python中可以使用 threading 模块来创建和管理线程。其中,Thread 类是最常用的线程类,可以通过继承该类来自定义线程对象,也可以直接调用 threading.Thread(target=func) 方法来创建线程对象。以下是一个简单的创建线程的示例: import threading def hello(): print(&q…

    python 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部