简单入门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 技术干货!如果觉得有用,记得收藏本文!

相关推荐
还是大剑师兰特10 分钟前
Stats.js 插件详解及示例(完全攻略)
前端·大剑师·stats
前端小超超11 分钟前
Vue计算属性computed:可写与只读的区别
前端·javascript·vue.js
wh_xia_jun27 分钟前
MODNet 本地抠图项目指南
python
IT_陈寒1 小时前
SpringBoot实战:3个隐藏技巧让你的应用性能飙升50%
前端·人工智能·后端
weixin199701080161 小时前
唯品会商品详情页前端性能优化实战
前端·性能优化
老歌老听老掉牙1 小时前
Python星号参数深度解析
python·参数·星号
爱学习的程序媛1 小时前
【Web前端】Pinia状态管理详解
前端·vue.js·typescript
爱学习的程序媛1 小时前
“数字孪生”详解与前端技术栈
前端·人工智能·计算机视觉·智慧城市·信息与通信
海石1 小时前
微信小程序开发02:原始人也能看懂的着色器与视频处理
前端·微信小程序·视频编码
程序员Sunday1 小时前
Claude Code 生态爆发:5个必知的新工具
前端·人工智能·后端