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开发 #程序员 #编程教程 #效率提升 #装饰器

相关推荐
猿界零零七3 小时前
pip install mxnet 报错解决方案
python·pip·mxnet
不只会拍照的程序猿5 小时前
《嵌入式AI筑基笔记02:Python数据类型01,从C的“硬核”到Python的“包容”》
人工智能·笔记·python
Jay_Franklin5 小时前
Quarto与Python集成使用
开发语言·python·markdown
Oueii6 小时前
Django全栈开发入门:构建一个博客系统
jvm·数据库·python
2401_831824967 小时前
使用Fabric自动化你的部署流程
jvm·数据库·python
njidf7 小时前
Python日志记录(Logging)最佳实践
jvm·数据库·python
@我漫长的孤独流浪7 小时前
Python编程核心知识点速览
开发语言·数据库·python
宇擎智脑科技7 小时前
A2A Python SDK 源码架构解读:一个请求是如何被处理的
人工智能·python·架构·a2a
2401_851272997 小时前
实战:用Python分析某电商销售数据
jvm·数据库·python
vx_biyesheji00017 小时前
Python 全国城市租房洞察系统 Django框架 Requests爬虫 可视化 房子 房源 大数据 大模型 计算机毕业设计源码(建议收藏)✅
爬虫·python·机器学习·django·flask·课程设计·旅游