简单入门Python装饰器

引言

在Python中,装饰器(Decorator)是一种强大的工具,它使用简单的@符号语法,却能实现令人惊叹的代码增强功能。

装饰器初体验

1.1 最简单的装饰器示例

python 复制代码
def simple_decorator(func):
    def wrapper():
        print("函数执行前...")
        func()
        print("函数执行后...")
    return wrapper

@simple_decorator
def say_hello():
    print("Hello!")

say_hello()
"""
输出:
函数执行前...
Hello!
函数执行后...
"""

1.2 装饰器的本质

装饰器本质上是一个高阶函数,它:

  1. 接受一个函数作为参数
  2. 返回一个新函数
  3. 通常在不修改原函数代码的情况下增强其功能

@decorator 只是语法糖,等价于:

python 复制代码
def say_hello(): ...
say_hello = decorator(say_hello)

为什么需要装饰器?

2.1 代码复用:DRY原则

避免重复代码(Don't Repeat Yourself):

python 复制代码
import time

# 没有装饰器的重复代码
def funco1():
    start = time.time()
    # 函数逻辑...
    time.sleep(2)
    end = time.time()
    print(f"函数 {funco1.__name__} 耗时: {end-start}秒")

def funco2():
    start = time.time()
    # 函数逻辑...
    time.sleep(3)
    end = time.time()
    print(f"函数 {funco2.__name__} 耗时: {end-start}秒")

def timing(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

@timing
def func1():
    # 函数逻辑...
    time.sleep(2)
    print('func1 ....')

@timing
def func2():
    time.sleep(3)
    # 函数逻辑...
    print('func2 ....')

if __name__ == '__main__':
    funco1()
    funco2()
    func1()
    func2()

2.2 分离关注点

将业务逻辑与横切关注点(如日志、权限检查)分离:

python 复制代码
@login_required
@log_execution
def delete_user(user_id):
    # 纯业务逻辑
    ...

装饰器进阶用法

3.1 带参数的装饰器

python 复制代码
def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(num_times=3)
def greet(name):
    print(f"Hello {name}")

greet("Alice")
"""
Hello Alice
Hello Alice
Hello Alice
"""

3.2 保留原函数元信息

使用functools.wraps保持原函数的__name__等属性:

python 复制代码
from functools import wraps

def logged(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"调用 {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

3.3 类装饰器

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"调用次数: {self.num_calls}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()  # 输出调用次数和Hello!
say_hello()  # 输出调用次数和Hello!

"""
调用次数: 1
Hello!
调用次数: 2
Hello!
"""

结语

点个赞,关注我获取更多实用 Python 技术干货!如果觉得有用,记得收藏本文!

相关推荐
浩星3 分钟前
iframe引入界面有el-date-picker日期框,点击出现闪退问题处理
前端·vue.js·elementui
技术钱5 分钟前
element plus 多个form校验
前端
flashlight_hi12 分钟前
LeetCode 分类刷题:2563. 统计公平数对的数目
python·算法·leetcode
java1234_小锋13 分钟前
Scikit-learn Python机器学习 - 特征预处理 - 归一化 (Normalization):MinMaxScaler
python·机器学习·scikit-learn
yume_sibai15 分钟前
HTML HTML基础(3)
前端·html
米花丶22 分钟前
JSBridge安全通信:iOS/Android桥对象差异与最佳实践
前端·webview
星空的资源小屋25 分钟前
网易UU远程,免费电脑远程控制软件
人工智能·python·pdf·电脑
IMER SIMPLE32 分钟前
人工智能-python-深度学习-神经网络-MobileNet V1&V2
人工智能·python·深度学习
eleqi1 小时前
Python+DRVT 从外部调用 Revit:批量创建楼板
python·系统集成·revit·外部调用·drvt·自动化生产流水线
萌萌哒草头将军1 小时前
🚀🚀🚀 Oxc 恶意扩展警告;Rolldown 放弃 CJS 支持;Vite 发布两个漏洞补丁版本;Rslib v0.13 支持 ts-go
前端·javascript·vue.js