Python 装饰器使用技巧

73 阅读4分钟

1. 简单的时间统计装饰器

目的:计算函数执行时间,了解性能。

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timing_decorator
def example_function(n):
    sum(range(n))

example_function(1000000)

解释:这个装饰器记录了被装饰函数的开始和结束时间,然后计算并打印出耗时。它使用了*args 和 **kwargs 来保持函数的通用性。

2. 参数验证装饰器

用途:确保函数输入参数满足特定条件。

def positive_number_decorator(func):
    def wrapper(number):
        if number < 0:
            raise ValueError("Number must be positive.")
        return func(number)
    return wrapper

@positive_number_decorator
def square(number):
    return number ** 2

try:
    print(square(-5))
except ValueError as e:
    print(e)

技巧:通过抛出异常来处理不满足条件的情况,保持函数接口的清晰。

3. 缓存装饰器

目的:提高效率,避免重复计算。

from functools import lru_cache

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

print(fibonacci(30))  # 只计算一次

注意:lru_cache是一个内置的缓存实现,非常适合用于耗时的计算任务。

4. 日志记录装饰器

用途:自动记录函数调用信息。

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

@log_decorator
def add(a, b):
    return a + b

add(5, 3)

技巧:这有助于调试和监控程序运行。

5. 类方法装饰器

场景:在类方法上添加额外逻辑。

def class_method_logger(cls_method):
    def wrapper(self, *args, **kwargs):
        print(f"Calling method '{cls_method.__name__}' on {self.__class__.__name__}")
        return cls_method(self, *args, **kwargs)
    return wrapper

class MyClass:
    @class_method_logger
    def say_hello(self, name):
        print(f"Hello, {name}")

MyClass().say_hello("World")

理解:装饰器同样适用于类方法,增加类行为的灵活性。

6. 异常处理装饰器

目的:统一异常处理逻辑。

def handle_exceptions(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print(f"Error in {func.__name__}: {e}")
    return wrapper

@handle_exceptions
def divide(a, b):
    return a / b

divide(10, 0)  # 安全地处理除零错误

7. 计数装饰器

应用场景:跟踪函数调用次数。

class Counter:
    def __init__(self, func):
        self.func = func
        self.calls = 0

    def __call__(self, *args, **kwargs):
        self.calls += 1
        print(f"Call {self.calls} of {self.func.__name__}")
        return self.func(*args, **kwargs)

@Counter
def greet():
    print("Hello!")

greet()
greet()

8. 参数默认值检查装饰器

使用:确保函数参数符合预期值。

def check_parameters(expected):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for key, value in kwargs.items():
                if key in expected and value != expected[key]:
                    raise ValueError(f"Invalid value for {key}. Expected {expected[key]}, got {value}.")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@check_parameters({"difficulty": "easy"})
def start_game(difficulty):
    print(f"Starting game with difficulty level {difficulty}.")

start_game(difficulty="medium")  # 触发异常

9. 使用列表推导式处理字符串

技巧 : 将字符串转换为列表进行操作。

s = "hello"
upper_list = [c.upper() for c in s]
print(''.join(upper_list))  # 输出: HELLO

解释 : 列表推导式结合join()方法,可以实现字符串字符的批量操作。

10. 替换字符串

技巧 : 使用replace()。

text = "hello, hello, world!"
new_text = text.replace("hello", "hi", 2)  # 替换前两个"hello"
print(new_text)  # 输出: hi, hi, world!

解释 : replace()方法可以替换字符串中的指定部分,第三个参数限制替换次数。

11. 字符串的长度

技巧 : 使用len()函数。

s = "Python"
length = len(s)
print(length)  # 输出: 6

解释 : 简单但重要,len()函数返回字符串长度。

12. 检查字符串开头或结尾

技巧 : 使用startswith(), endswith()。

filename = "example.txt"
if filename.endswith(".txt"):
    print("It's a text file.")

解释 : 这两个方法检查字符串是否以特定前缀或后缀开始或结束。

13. 使用正则表达式

技巧 : 引入re模块进行复杂模式匹配。

import re
text = "My email is example@example.com"
email = re.search(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Z|a-z]{2,}\b', text)
if email:
    print(email.group())  # 输出: example@example.com

解释 : 正则表达式是强大的文本处理工具,适用于复杂的字符串匹配和提取。

14. 遍历字符串

技巧 : 直接遍历字符串。

s = "Python"
for char in s:
    print(char)

实战案例:Web请求计时与日志记录

假设我们有一个简单的Web请求函数,我们想要记录每次请求的时间并简单记录日志。

import requests
from datetime import datetime

def request_logger(url):
    def decorator(func):
        def wrapper(*args, **kwargs):
            start = datetime.now()
            response = func(url, *args, **kwargs)
            end = datetime.now()
            print(f"Request to {url} completed in {end - start}. Status Code: {response.status_code}")
            return response
        return wrapper
    return decorator

@request_logger("https://api.example.com/data")
def make_request(url):
    return requests.get(url)

make_request()

分析:这个案例展示了如何结合使用多个功能(计时和日志记录)于一个装饰器中,以监控API调用。在实际开发中,这样的装饰器可以极大地帮助监控和优化服务性能。