Python装饰器

Python装饰器是一种强大的功能,用于修改或扩展函数或方法的行为。装饰器本质上是一个函数,它接受一个函数作为输入,并返回一个新的函数,通常是对输入函数的增强或修改。装饰器在代码中广泛用于日志记录、性能分析、验证、权限检查等方面,可以提高代码的可维护性和可复用性。

import datetime

# 定义一个装饰器函数
def info_log(func):
    def wrapper():
        print(datetime.datetime.now())
        func()
        print(datetime.datetime.now())
    return wrapper

# 使用装饰器
@info_log
def say_hello():
    print("Hello!")

# 调用被装饰的函数
say_hello()

在这个示例中,info_log 是一个装饰器函数,它接受一个函数 func 作为参数,并返回了一个新的函数 wrapperwrapper 函数在调用 func 之前和之后分别打印了一些信息。通过在 say_hello 函数上方使用 @info_log,我们将 say_hello 函数装饰了起来,使其在调用时会执行额外的操作。

当运行上述代码时,输出将如下所示:

2023-10-08 22:31:01.191623
Hello!
2023-10-08 22:31:01.191623

这只是装饰器的一个简单示例。Python中有许多内置的装饰器,也可以创建自定义装饰器来满足特定需求。装饰器是Python中强大而灵活的工具,可用于各种编程任务。

它们在标准库中提供了有用的功能,包括:

  1. @staticmethod: 将一个方法装饰为静态方法。
  2. @classmethod: 将一个方法装饰为类方法。
  3. @property: 将一个方法装饰为属性,可以让方法像访问属性一样调用。
  4. @abstractmethod: 用于定义抽象基类中的抽象方法,必须由子类实现。
  5. @abstractmethod: 用于定义抽象基类中的抽象属性,必须由子类实现。
  6. @wraps: 用于保留被装饰函数的元数据,通常在自定义装饰器中使用。
  7. @functools.lru_cache: 用于实现缓存,可以缓存函数的计算结果以提高性能。

示例:

from functools import wraps

# 使用@property定义属性装饰器
class MyClass:
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        self._value = new_value

# 使用@staticmethod定义静态方法
class MathUtils:
    @staticmethod
    def add(x, y):
        return x + y

# 使用@classmethod定义类方法
class Date:
    def __init__(self, day, month, year):
        self.day = day
        self.month = month
        self.year = year

    @classmethod
    def from_string(cls, date_string):
        day, month, year = map(int, date_string.split('-'))
        return cls(day, month, year)

# 使用@abstractmethod定义抽象方法
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

# 使用@functools.lru_cache实现缓存
from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# 使用@wraps保留元数据
def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """My Wrapper Docstring"""
        return func(*args, **kwargs)
    return wrapper

装饰器是Python中一种强大的编程工具,它用于修改或扩展函数或方法的行为,而无需修改它们的源代码。装饰器通常用于以下场景:

1. **日志记录**: 装饰器可以用于记录函数的调用信息、参数和返回值,以便进行调试和性能分析。

2. **权限控制**: 装饰器可以用于检查用户是否有足够的权限来执行特定操作,例如登录验证、角色检查等。

3. **性能优化**: 装饰器可以用于缓存函数的计算结果,以避免重复计算,提高性能。

4. **异常处理**: 装饰器可以用于捕获函数内部的异常并进行处理,以便进行错误处理或日志记录。

5. **事务管理**: 装饰器可以用于实现数据库事务管理,确保在一系列数据库操作中要么全部成功,要么全部失败。

6. **计时和统计**: 装饰器可以用于测量函数的执行时间,或统计函数的调用次数。

7. **单例模式**: 装饰器可以用于确保某个类只有一个实例。

8. **API路由**: 在Web框架中,装饰器可以用于将函数映射到特定的URL路由,实现API的路由功能。

9. **缓存**: 装饰器可以用于缓存函数的结果,以减少重复计算。

装饰器的概念非常灵活,它允许开发人员以声明性的方式来修改函数或方法的行为,而不需要修改它们的源代码。这提高了代码的可重用性和可维护性,使得代码更加模块化和清晰。

示例:

# 装饰器示例,记录函数调用日志
def log_function_call(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(f"Calling {func.__name__} with args={args} and kwargs={kwargs}")
        return result
    return wrapper

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

add(2, 3)  # 输出:Calling add with args=(2, 3) and kwargs={}

在这个示例中,`log_function_call` 装饰器记录了 `add` 函数的调用信息,而不需要修改 `add` 函数的源代码。

一些常用的第三方装饰器。

1、Flask: Flask 是一个流行的 Python Web 框架,它提供了许多与 Web 开发相关的装饰器,如 @app.route 用于路由 URL,@app.before_request@app.after_request 用于处理请求前和请求后的逻辑。

from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run()

2、pytest: pytest 是一个流行的 Python 测试框架,它提供了多个装饰器,如 @pytest.fixture 用于创建测试夹具,@pytest.mark.parametrize 用于参数化测试等。

import pytest

@pytest.mark.parametrize("input, expected", [(1, 2), (2, 4), (3, 6)])
def test_multiply_by_two(input, expected):
    result = input * 2
    assert result == expected

@pytest.mark.skip(reason="Test not implemented yet")
def test_function_to_be_implemented():
    assert True

@pytest.mark.xfail(reason="Expected to fail, but not a showstopper")
def test_expected_failure():
    assert False

3、在 unittest 中,可以使用 @unittest.TestCase 类的装饰器方法(如 @unittest.skip@unittest.expectedFailure)来标记测试方法,以实现跳过测试或标记预期失败。

import unittest

class MyTestCase(unittest.TestCase):

    @unittest.skip("Skip this test for now")
    def test_skip_this(self):
        self.assertTrue(False)

    @unittest.expectedFailure
    def test_expected_failure(self):
        self.assertTrue(False)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值