简单入门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 小时前
什么?还不知道git cherry pick?
前端·javascript·git
白兰地空瓶4 小时前
🏒 前端 AI 应用实战:用 Vue3 + Coze,把宠物一键变成冰球运动员!
前端·vue.js·coze
吴佳浩4 小时前
Python入门指南(六) - 搭建你的第一个YOLO检测API
人工智能·后端·python
superman超哥5 小时前
仓颉语言中基本数据类型的深度剖析与工程实践
c语言·开发语言·python·算法·仓颉
Liu.7745 小时前
vue3使用vue3-print-nb打印
前端·javascript·vue.js
Learner__Q6 小时前
每天五分钟:滑动窗口-LeetCode高频题解析_day3
python·算法·leetcode
————A6 小时前
强化学习----->轨迹、回报、折扣因子和回合
人工智能·python
松涛和鸣6 小时前
Linux Makefile : From Basic Syntax to Multi-File Project Compilation
linux·运维·服务器·前端·windows·哈希算法
dly_blog6 小时前
Vue 逻辑复用的多种方案对比!
前端·javascript·vue.js
万少6 小时前
HarmonyOS6 接入分享,原来也是三分钟的事情
前端·harmonyos