Python 装饰器案例

下面这段代码可以直接复制到一个 .py 文件中运行,覆盖普通装饰器、计时装饰器、带参数装饰器、权限检查和内置装饰器。

from functools import wraps
from time import perf_counter, sleep
 
 
def trace(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"call {func.__name__}")
        return func(*args, **kwargs)
 
    return wrapper
 
 
def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = perf_counter()
        result = func(*args, **kwargs)
        end = perf_counter()
        print(f"{func.__name__} cost {end - start:.6f}s")
        return result
 
    return wrapper
 
 
def repeat(times):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            result = None
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
 
        return wrapper
 
    return decorator
 
 
def require_role(role):
    def decorator(func):
        @wraps(func)
        def wrapper(user, *args, **kwargs):
            if user.get("role") != role:
                raise PermissionError("permission denied")
            return func(user, *args, **kwargs)
 
        return wrapper
 
    return decorator
 
 
@trace
def add(a, b):
    return a + b
 
 
@timer
def slow_task():
    sleep(0.01)
    return "done"
 
 
@repeat(3)
def say_hi(name):
    print(f"hi {name}")
 
 
@require_role("admin")
def delete_post(user, post_id):
    return f"user {user['name']} deleted post {post_id}"
 
 
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score
 
    @property
    def passed(self):
        return self.score >= 60
 
    @classmethod
    def from_dict(cls, data):
        return cls(data["name"], data["score"])
 
    @staticmethod
    def is_valid_score(score):
        return 0 <= score <= 100
 
 
def main():
    print(add(1, 2))
    print(slow_task())
    say_hi("Tom")
 
    admin = {"name": "Lucy", "role": "admin"}
    print(delete_post(admin, 1001))
 
    student = Student.from_dict({"name": "Jack", "score": 72})
    print(student.name, student.passed)
    print(Student.is_valid_score(101))
 
 
if __name__ == "__main__":
    main()