讲师中心 微信公众号
AI工具推荐 视频效率加速

Python中如何使用装饰器?

星浩君_4667

星浩君_4667

发布时间:2025-04-26 15:57:01

|

764人浏览过

|

来源于php中文网

原创

python装饰器是用于修改或增强函数或类行为的工具。1) 装饰器可以动态添加功能,如日志记录和性能监控。2) 它们本质上是接受函数并返回新函数的函数。3) 使用装饰器时需注意保留函数元数据和执行顺序。4) 建议保持装饰器简单,并在需要时使用类装饰器。

Python中如何使用装饰器?

在Python中,装饰器是一种非常强大的工具,用于修改或增强函数或类的行为。它们就像魔法一样,可以在不改变原始函数代码的情况下,动态地添加功能。这篇文章将深入探讨Python装饰器的使用方法、原理以及一些实用的技巧。

让我们从最基本的装饰器开始吧。假设你有一个简单的函数,你想在它执行前后打印一些日志信息。没有装饰器,你可能需要手动修改函数:

def my_function():
    print("Function is running")

print("Before function call")
my_function()
print("After function call")

但是,使用装饰器,我们可以这样做:

立即学习“Python免费学习笔记(深入)”;

def log_decorator(func):
    def wrapper():
        print("Before function call")
        func()
        print("After function call")
    return wrapper

@log_decorator
def my_function():
    print("Function is running")

my_function()

在这个例子中,log_decorator 是一个装饰器,它接受一个函数 func 作为参数,并返回一个新的 wrapper 函数。这个 wrapper 函数在调用原始函数前后添加了日志打印。通过 @log_decorator 语法,我们可以轻松地将这个装饰器应用到 my_function 上。

现在,让我们深入了解装饰器的工作原理。装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。这个新的函数通常被称为“包装器”(wrapper),它可以调用原始函数,并在其前后执行额外的操作。

装饰器的优势在于它们可以复用。你可以定义一个装饰器,然后应用到多个函数上,而不必重复编写相同的代码。例如,如果你想为多个函数添加性能监控,你可以这样做:

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.4f} seconds to run.")
        return result
    return wrapper

@timing_decorator
def slow_function():
    time.sleep(2)
    print("Slow function finished")

@timing_decorator
def fast_function():
    print("Fast function finished")

slow_function()
fast_function()

在这个例子中,timing_decorator 可以应用到多个函数上,方便地监控它们的执行时间。

macOS UI 自动化技能包 —— 用 Python 控制你的 Mac
macOS UI 自动化技能包 —— 用 Python 控制你的 Mac

让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限

下载

然而,装饰器也有一些需要注意的地方。首先,装饰器会改变函数的身份,这可能会影响一些依赖于函数名称的代码。为了解决这个问题,你可以使用 functools.wraps 来保留原始函数的元数据:

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Something is happening before the function is called.")
        result = func(*args, **kwargs)
        print("Something is happening after the function is called.")
        return result
    return wrapper

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

say_hello()

这样,say_hello.__name__ 仍然会返回 "say_hello",而不是 "wrapper"。

另一个需要注意的是,装饰器会在模块导入时立即执行。如果你的装饰器有副作用,你可能需要小心。例如:

def register(func):
    print(f"Registering function: {func.__name__}")
    return func

@register
def foo():
    pass

@register
def bar():
    pass

在这个例子中,导入模块时就会打印出注册信息。

最后,分享一些我使用装饰器的经验和建议:

  1. 保持装饰器简单:装饰器的逻辑应该尽量简单明了,避免复杂的业务逻辑。如果装饰器变得太复杂,考虑将其拆分为多个装饰器或使用类装饰器。

  2. 使用类装饰器:有时候,使用类来实现装饰器会更灵活,特别是当你需要维护一些状态时。例如,缓存装饰器可以使用类来实现:

class Cached:
    def __init__(self, func):
        self.func = func
        self.cache = {}

    def __call__(self, *args):
        if args in self.cache:
            return self.cache[args]
        result = self.func(*args)
        self.cache[args] = result
        return result

@Cached
def expensive_function(n):
    print(f"Calculating {n}")
    return n * n

print(expensive_function(2))  # 输出: Calculating 2, 然后 4
print(expensive_function(2))  # 直接返回 4,不再计算
  1. 注意装饰器的执行顺序:多个装饰器应用到同一个函数时,它们的执行顺序是从下到上。例如:
def decorator1(func):
    def wrapper():
        print("Decorator 1")
        return func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("Decorator 2")
        return func()
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("Hello!")

say_hello()

输出将是:

Decorator 1
Decorator 2
Hello!
  1. 调试装饰器:调试装饰器可能有些棘手,因为它们会改变函数的调用栈。你可以使用 pdb 或其他调试工具,但记得装饰器会影响函数的名称和文档字符串。

总之,装饰器是Python中一个非常有用的特性。它们可以帮助你编写更简洁、更具可读性的代码,但也要注意它们的使用方式和可能带来的问题。通过不断实践和总结经验,你会越来越熟练地使用装饰器来提升你的代码质量。

相关文章

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

相关专题

更多
js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1838

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2944

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6244

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

6149

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

7734

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

11714

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

6039

2025.07.29

c++字符串相关教程
c++字符串相关教程

本专题整合了c++字符串相关教程,阅读专题下面的文章了解更多详细内容。

6707

2025.08.07

Uvicorn 报错与问题解决教程
Uvicorn 报错与问题解决教程

本专题汇总了Uvicorn服务器常见问题与报错解决的教程合集,涵盖启动失败、端口占用、模块导入错误、事件循环冲突及热重载失效等典型故障的排查思路。同时整理了多进程与Worker配置、SSL/HTTPS证书报错、跨域与代理配置等实战解决方案,助你快速定位并解决Uvicorn运行中的各类问题。

0

2026.11.02

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn