1 分钟读懂:Python 装饰器

每天1分钟,轻松懂 Python

这是一份有基础、有深度的 Python 核心技术手册

函数与闭包

1、函数是一等公民

Python 中函数可以赋值给变量;可以作为参数传递;也可以在函数里定义函数。

示例:将函数作为参数传递

python 复制代码
def func(message):  
    print(f"Got message: {message}")  

send_message = func  # 函数赋值给变量  
send_message("hello world")  # 这里调用:Got message: hello world  
2、函数嵌套与闭包

在函数内定义子函数,最后,返回子函数。在子函数可以访问外层函数变量。

python 复制代码
def outer():  
    x = 1  
    def inner():  
        print(x)  # 访问 outer 的变量 x  
    return inner  

fn = outer()  
fn()  # 输出 1(闭包保留外层变量引用 )  

核心语法

1、简单的装饰器

装饰器是用于 "包装函数",在不修改原函数的前提下,添加额外逻辑(如日志、权限校验 )。

python 复制代码
def my_decorator(func):  
    def wrapper():  
        print("wrapper of decorator")  
        func()  
    return wrapper  

@my_decorator  # 语法等价于 greet = my_decorator(greet)  
def greet():  
    print("hello world")  

greet()  
# 输出:  
# wrapper of decorator  
# hello world  
2、带参数的装饰器

*args**kwargs 可以接收任意数量和类型的参数。

python 复制代码
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
    return wrapper

@my_decorator
def greet(name, message):
    print(f"Hi {name}, {message}")


greet("Mr.Wang", "Good to see you.")

# 输出
# wrapper of decorator
# Hi Mr.Wang, Good to see you.

保留函数原信息

被装饰后函数,会默认丢失原信息(如 __name__ ),需要用 functools.wraps 修复:

python 复制代码
import functools  

def my_decorator(func):  
    @functools.wraps(func)  # 保留原函数信息 <<<<<<<<
    def wrapper(*args, **kwargs):  
        print("wrapper of decorator")  
        func(*args, **kwargs)  
    return wrapper  

@my_decorator  
def greet():  
    print("hello world")  

print(greet.__name__)  # 输出 'greet'(否则为 'wrapper' )  

类装饰器 和 多层装饰器

1、类装饰器

用类实现装饰器,通过 __call__ 方法拦截函数调用:

python 复制代码
class CountCalls:  
    def __init__(self, func):  
        self.func = func  
        self.num_calls = 0  

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

@CountCalls
def greet(name):
    print(f"Hi {name}")


greet("Mr.Wang")
# 输出:
# Call 1 of greet
# Hi Mr.Wang

greet("Mr.Li")
# 输出:
# Call 2 of greet
# Hi Mr.Li
2、多层装饰器

多个装饰器叠加,执行顺序为从外到内包裹,从内到外执行

python 复制代码
@decorator1  
@decorator2  
def greet():  
    print("hello world")  
    
# 执行逻辑等价于 greet = decorator1(decorator2(greet))  
# 执行时:decorator1 的 wrapper → decorator2 的 wrapper → 原函数  

使用场景

1、身份认证

校验用户登录状态,未登录则拦截操作:

python 复制代码
import functools  

def authenticate(func):  
    @functools.wraps(func)  
    def wrapper(*args, **kwargs):  
        if not check_login_state():  # 自定义校验逻辑
            raise Exception("Authentication failed")  
        return func(*args, **kwargs)  
    return wrapper  

@authenticate  
def post_comment(content):  
    print(f"发布评论:{content}")  
2、日志记录

统计函数执行时间、打印调用日志:

python 复制代码
import time  
import functools  

def log_execution_time(func):  
    @functools.wraps(func)  
    def wrapper(*args, **kwargs): 
        start = time.time()  
        result = func(*args, **kwargs)  
        end = time.time()  
        print(f"{func.__name__} 执行耗时:{end - start} 秒")  # 记录耗时
        return result  
    return wrapper  

@log_execution_time  
def train_model():  
    time.sleep(2)  # 模拟耗时操作  
3、输入合法性检查

预处理函数参数,确保符合规则:

python 复制代码
import functools  

def validate_params(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 示例:校验第一个参数为数字
        if not isinstance(args[0], (int, float)):  
            raise ValueError("参数必须为数字")
        return func(*args, **kwargs)

    return wrapper

@validate_params  
def process_data(data):  
    print(f"处理数据:{data}")  
4、缓存优化

@lru_cache 会缓存函数参数和结果,避免重复计算(如 functools.lru_cache ):

python 复制代码
import functools  

@functools.lru_cache(maxsize=128)
def cal(n):
    print(f"开始执行 cal. 参数:{n}")
    time.sleep(3)
    return n * 2


cal(100)
cal(100)
cal(100)

# 重复调用 cal(100) 时,只输出一个 "开始执行 cal. 参数:100"

-------- 写在最后 --------

关注我,每天1分钟,轻松懂 Python

我的同名公众号正在连载《FastAPI 开发实战》、《Python 核心技术》、《职场》。


点赞 :如果觉得有收获,点赞支持一下吧!

分享 :分享给身边同样对Python感兴趣的朋友!

关注我 :不要错过每一篇 Python 实战内容!


#Python #FastAPI #API #Web开发 #程序员 #编程教程 #效率提升 #装饰器

相关推荐
wazmlp0018873691 小时前
python第三次作业
开发语言·python
深蓝电商API1 小时前
住宅代理与数据中心代理在爬虫中的选择
爬虫·python
历程里程碑2 小时前
普通数组----合并区间
java·数据结构·python·算法·leetcode·职场和发展·tornado
weixin_395448912 小时前
mult_yolov5_post_copy.c_cursor_0205
c语言·python·yolo
执风挽^2 小时前
Python基础编程题2
开发语言·python·算法·visual studio code
纤纡.3 小时前
PyTorch 入门精讲:从框架选择到 MNIST 手写数字识别实战
人工智能·pytorch·python
kjkdd3 小时前
6.1 核心组件(Agent)
python·ai·语言模型·langchain·ai编程
小镇敲码人3 小时前
剖析CANN框架中Samples仓库:从示例到实战的AI开发指南
c++·人工智能·python·华为·acl·cann
萧鼎3 小时前
Python 包管理的“超音速”革命:全面上手 uv 工具链
开发语言·python·uv
alvin_20054 小时前
python之OpenGL应用(二)Hello Triangle
python·opengl