【python装饰器:看懂这10个例子你就掌握了!】

news2024/10/6 1:37:19

在这里插入图片描述

基本说明

Python 装饰器是一种函数,它可以用来修改其他函数的功能。它是 Python 中的一项高级编程技术,也是 Python 中比较重要的语法之一。

简单来说,装饰器就是一个函数,它可以接受一个函数作为参数,并返回一个函数。通过在函数定义前使用 @ 符号和装饰器函数名,可以把该函数传递给装饰器函数,并将装饰器函数返回的函数对象赋值给该函数名。这样,在函数被调用时,实际上是先调用了装饰器函数,然后再调用被装饰的函数。

装饰器在 Python 中的应用非常广泛,它可以用来实现很多功能,比如:

  1. 计时器:可以用装饰器来记录函数的执行时间。
  2. 缓存:可以用装饰器来缓存函数的执行结果,避免重复计算。
  3. 认证和授权:可以用装饰器来对函数进行认证和授权,限制用户访问权限。
  4. 日志记录:可以用装饰器来记录函数的执行日志,便于排查问题。
  5. 重试:可以用装饰器来对函数进行重试,确保函数能够成功执行。
  6. 输入验证:可以用装饰器来对函数的输入参数进行验证,确保输入合法。
  7. 错误处理:可以用装饰器来对函数的错误进行处理,防止程序崩溃。

代码示例

以下是一些 Python 常用的装饰器示例:

  1. 计时器装饰器:可以用来统计函数的执行时间。
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print("Function {0} takes {1:.6f} seconds to execute.".format(func.__name__, end_time - start_time))
        return result
    return wrapper

@timer
def my_func():
    time.sleep(1)

my_func()
  1. 缓存装饰器:可以用来缓存函数的结果,避免重复计算。
def cache(func):
    cached_results = {}
    def wrapper(*args, **kwargs):
        cache_key = (args, tuple(kwargs.items()))
        if cache_key in cached_results:
            return cached_results[cache_key]
        result = func(*args, **kwargs)
        cached_results[cache_key] = result
        return result
    return wrapper

@cache
def fibonacci(n):
    if n <= 1:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))
  1. 日志装饰器:可以用来记录函数的执行日志。
def log(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print("Function {0} was called with arguments {1} and {2}, and returned {3}.".format(
            func.__name__, args, kwargs, result))
        return result
    return wrapper

@log
def my_func(x, y):
    return x + y

my_func(1, 2)
  1. 并发执行装饰器:可以用来让多个函数并发执行。
import threading

def concurrent(func):
    def wrapper(*args, **kwargs):
        t = threading.Thread(target=func, args=args, kwargs=kwargs)
        t.start()
        return t
    return wrapper

@concurrent
def my_func():
    print("Function is running.")

t = my_func()
t.join()

在这个示例中,定义了一个装饰器函数 concurrent,它接受一个函数作为参数,并返回一个新的函数 wrapper。在 wrapper 函数内部,先创建一个新的线程,并将被装饰的函数传递给该线程。然后,通过 @concurrent 的语法糖来装饰函数 my_func,使其具有并发执行的能力。当调用 my_func 函数时,实际上会先调用 concurrent 函数,然后创建一个新的线程,并在该线程中执行 my_func 函数。最终,可以通过 t.join() 等待该线程执行完成。

  1. 参数化装饰器:可以用来给装饰器传递参数。
def repeat(num):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(num):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def say_hello():
    print("Hello")

say_hello()

在这个示例中,定义了一个参数化装饰器函数 repeat,它接受一个参数 num,并返回一个新的装饰器函数 decorator。在 decorator 函数内部,定义了一个新的函数 wrapper,用来重复调用被装饰的函数。然后,通过 @repeat(3) 的语法糖来装饰函数 say_hello,使其重复调用 3 次。当调用 say_hello 函数时,实际上会先调用 repeat(3) 函数,然后再调用返回的 decorator 函数,最终得到一个重复调用 3 次的 say_hello 函数。

  1. 类装饰器:可以用来装饰类和类的方法。
class LogDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("Function {0} was called with arguments {1} and {2}.".format(
            self.func.__name__, args, kwargs))
        return self.func(*args, **kwargs)

@LogDecorator
def my_func(x, y):
    return x + y

result = my_func(1, 2)
print(result)

在这个示例中,定义了一个类装饰器 LogDecorator,它接受一个函数作为参数,并实现了 __init____call__ 方法。在 __call__ 方法内部,先输出函数的调用日志,然后再调用被装饰的函数,并返回函数的返回值。然后,通过 @LogDecorator 的语法糖来装饰函数 my_func,使其具有记录函数调用日志的功能。当调用 my_func 函数时,实际上会先调用 LogDecorator__init__ 方法和 __call__ 方法,最终输出函数的调用日志,并返回函数的返回值。

  1. 类方法装饰器:可以用来装饰类方法,并对类方法的调用进行处理。
class LogCalls:
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return self.__class__(self.func.__get__(instance, owner))

    def __call__(self, *args, **kwargs):
        print("Method {0} was called with arguments {1} and {2}.".format(
            self.func.__name__, args, kwargs))
        return self.func(*args, **kwargs)

class MyClass:
    @LogCalls
    def my_method(self, x, y):
        return x + y

obj = MyClass()
result = obj.my_method(1, 2)
print(result)

在这个示例中,定义了一个类方法装饰器 LogCalls,它接受一个方法作为参数,并实现了 __get____call__ 方法。在 __get__ 方法内部,先判断装饰器所属的对象是否为类,如果是类,则返回装饰器对象本身;如果是实例,则返回一个新的装饰器对象,用来处理方法的调用。在 __call__ 方法内部,输出方法的调用日志,然后调用原始方法并返回其返回值。然后,通过 @LogCalls 的语法糖来装饰类 MyClass 的方法 my_method,使其具有记录方法调用日志的功能。当调用 my_method 方法时,实际上会先调用 LogCalls__get__ 方法和返回的新方法对象的 __call__ 方法,最终输出方法的调用日志,并返回方法的返回值。

  1. 参数检查装饰器:可以用来检查函数参数的类型和值是否符合要求。
def check_args(*types):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i, arg in enumerate(args):
                if not isinstance(arg, types[i]):
                    raise TypeError("Expected argument {0} to be {1}, but got {2}.".format(
                        i+1, types[i], type(arg)))
            return func(*args, **kwargs)
        return wrapper
    return decorator

@check_args(int, str)
def my_func(x, y):
    print("x = {0}, y = {1}".format(x, y))

my_func(1, "hello")

在这个示例中,定义了一个参数检查装饰器函数 check_args,它接受多个参数类型作为参数,并返回一个新的装饰器函数 decorator。在 decorator 函数内部,定义了一个新的函数 wrapper,用来检查函数参数的类型和值是否符合要求。然后,通过 @check_args(int, str) 的语法糖来装饰函数 my_func,使其具有参数检查的功能。当调用 my_func 函数时,实际上会先调用 check_args(int, str) 函数,然后再调用返回的 decorator 函数,最终检查函数参数的类型和值是否符合要求。

  1. 单例模式装饰器:可以用来实现单例模式,确保类只有一个实例对象。
def singleton(cls):
    instances = {}
    def getinstance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    def __init__(self, x):
        self.x = x

obj1 = MyClass(1)
obj2 = MyClass(2)
print(obj1.x)
print(obj2.x)
print(id(obj1))
print(id(obj2))

在这个示例中,定义了一个单例模式装饰器函数 singleton,它接受一个类作为参数,并返回一个新的函数 getinstance。在 getinstance 函数内部,先判断该类是否已经有一个实例对象,如果没有,则创建一个新的实例对象并返回;如果已经有一个实例对象,则直接返回该实例对象。然后,通过 @singleton 的语法糖来装饰类 MyClass,使其具有单例模式的功能。当创建 MyClass 类的实例对象时,实际上会先调用 singleton 函数,然后再调用返回的 getinstance 函数,最终返回一个唯一的实例对象。

  1. 性能优化装饰器:可以用来优化函数的性能,比如缓存结果、避免重复计算等。
import time

def memoize(func):
    cache = {}
    def wrapper(*args, **kwargs):
        key = args + tuple(sorted(kwargs.items()))
        if key not in cache:
            cache[key] = func(*args, **kwargs)
        return cache[key]
    return wrapper

@memoize
def my_func(x, y):
    time.sleep(1)
    return x + y

result1 = my_func(1, 2)
result2 = my_func(1, 2)
result3 = my_func(2, 3)
print(result1)
print(result2)
print(result3)

在这个示例中,定义了一个性能优化装饰器函数 memoize,它接受一个函数作为参数,并返回一个新的函数 wrapper。在 wrapper 函数内部,先计算函数的参数和关键字参数的哈希值,作为缓存的键。然后,判断该键是否已经存在于缓存中,如果存在,则直接返回缓存中的结果;如果不存在,则调用原始函数,并将计算结果保存到缓存中。然后,通过 @memoize 的语法糖来装饰函数 my_func,使其具有缓存计算结果的功能。当调用 my_func 函数时,如果函数的参数和关键字参数与之前的调用相同,则实际上会直接返回缓存中的结果,从而避免重复计算,提高函数的性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/457817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Obsidian+坚果云+FolderSync解决电脑端和安卓端同步方案

目录1.Obsidian电脑端准备 2.Obsidian安卓端准备 3.坚果云电脑端准备 4.坚果云手机端准备 5.FolderSync手机端准备 6.百度云冗余备份 1.Obsidian电脑端准备 这里以windows版本为例&#xff0c;下载后安装 1.Obsidian官网&#xff1a;https://obsidian.md/ 官网下载有时候…

电力电网行业IT运维方案

智能电网背景下&#xff0c;电力、电网企业信息化逐渐渗透到其业务链的各个环节&#xff0c;云计算、物联网、移动互联网等新技术的应用&#xff0c;更驱动信息化与业务创新深度融合。电力、电网企业集团信息系统群逐渐朝着一体化方向发展&#xff0c;信息链越来越长&#xff0…

银行数字化转型导师坚鹏:宏观经济趋势与资本行业机遇和挑战

2023年宏观经济趋势与资本行业机遇和挑战 课程背景&#xff1a; 很多学员存在以下问题&#xff1a; 不知道我国目前的宏观经济形势&#xff1f; 不清楚宏观环境对我国经济的影响&#xff1f; 不知道资本行业未来主要发展趋势&#xff1f; 课程特色&#xff1a; 精彩解…

基于php的校园校园兼职网站的设计与实现

摘要 近年来&#xff0c;信息技术在大学校园中得到了广泛的应用&#xff0c;主要体现在两个方面&#xff1a;一是学校管理系统&#xff0c;包括教务管理、行政管理和分校管理&#xff0c;是我国大学管理和信息传递的主要渠道。二是学生生活服务平台。而随着大学生毕业人数的年…

leetcode重点题目分类别记录(四)图论深入

文章目录 入度出度最大网络秩可以到达所有点的最少点数目 并查集省份数量等式方程的可满足性按字典序排列最小的等效字符串以图判树 二分图判断二分图 深度优先搜索封闭岛屿数量太平洋大西洋水流问题 广度优先搜索树上逃逸最短路径多源最短路径 拓扑排序DFS解决拓扑排序BFS解决…

MIPS指令集-mars-cpu

MIPS通用寄存器 MIPS有32个通用寄存器&#xff08;$0-$31&#xff09;&#xff0c;各寄存器的功能及汇编程序中使用约定如下&#xff1a; 下表描述32个通用寄存器的别名和用途 REGISTER NAME USAGE $0 $zero 常量0(constant value 0) $1 $at 保留给汇编器(Reserved f…

K近邻算法(手写代码+图像识别实践)

k近邻算法作为一个分类算法&#xff0c;他通过计算不同特征值之间的距离来进行分类&#xff0c;它的工作原理是存在一个样本集合作为训练样本集&#xff0c;且每个样本都存在一个标签&#xff0c;此时&#xff0c;输入一个新的样本不存在标签&#xff0c;我们通过计算这个新样本…

【Android车载系列】第10章 系统服务-SystemServer源码分析(API28)

1 SystemServer启动 &emps;&emps;SystemServer进程启动&#xff0c;首先从SystemServer.java文件的main()方法开始。 290 /** 291 * The main entry point from zygote. 292 */ 293 public static void main(String[] args) { 294 new SystemSe…

S32K3系列单片机开发笔记(SIUL是什么/配置引脚复用的功能·)

前言 今天花时间看了一下&#xff0c;SIUL2模块的相关内容&#xff0c;并参照文档&#xff0c;以及例程作了一些小记录&#xff0c;知道该如何使用这个外设&#xff0c;包括引脚的配置&#xff0c;中断配置&#xff0c;以及常用函数的使用等&#xff0c;但对其中的一些细节还需…

如何利用代码快速生成mapper.xml的<resultMap>

一&#xff0c;问题引入 当我们开发 mapper.xml ---->dao接层 ---->service接口---->serviceImp ---->controller层&#xff0c; 其中在mapper.xml编写查询语句的sql时会遇到sql查询到的结果 涉及到多张表的字段&#xff0c;或者单张表的字段过多时&#xff0c; 这…

Python文件处理

文章目录 1️⃣基本语法2️⃣读取文件⚜️读取整个文件read()⚜️with 关键词⚜️逐行读取 3️⃣写入文件⚜️写入文件write()⚜️写入数字⚜️追加内容到文件 4️⃣读取和写入二进制文件 简介 读完本篇你将学会文件的创建、读取、写入等。 1️⃣基本语法 在Python中使用文件的…

ThreadLocal机制解读和源码分析

目录 线程数据共享和安全 -ThreadLocal 什么是 ThreadLocal 代码演示 创建Dog.java 创建Pig.java T2DAO.java T2DAO T1解读set T1Service 解读 get ThreadLocalTest这个是换一种法 ThreadLocal 原理分析图 1. ThreadLocal 原理分析图(重点 set 和 get) 线程数据共…

Go Fuzzing:发现你未曾发现的漏洞

文章目录 Fuzzing(模糊测试)要求示例模拟crash 总结参考资料 Fuzzing(模糊测试) go fuzz文档 对于软件开发者而言&#xff0c;一项重要的任务就是确保程序的安全性。而其中一种风险就是软件中可能存在的漏洞。传统的测试方法往往需要耗费大量的时间和人力&#xff0c;而使用F…

【C++: 模块二 ---运算符、流程控制语句】

C&#xff1a; 模块二 ---运算符、流程控制语句 一、运算符&#xff1a;1.1算数运算符&#xff1a;1.2赋值运算符&#xff1a;1.3比较运算符&#xff1a;1.4逻辑运算符&#xff1a;1.5三目运算符&#xff1a; 二、程序流程结构2.1顺序结构&#xff1a;2.2选择结构&#xff1a;&…

ChatGPT免费第一版本

最近利用空余时间做了一个供大家免费体验的chatgpt国内可直接访问的版本 输入12345gpt.com可直接访问 贴上GPT给我回复的内容&#xff0c;&#x1f600; 当今社会&#xff0c;交流已经成为人们日常不可或缺的一部分。然而&#xff0c;随着技术的发展&#xff0c;人们对于交流工…

【Linux 裸机篇(七)】I.MX6U 中断系统

目录 一、中断向量表1. 中断向量偏移 二、中断系统简介1. 创建中断向量表 三、GIC 控制器简介1. 中断 ID 四、GIC 逻辑分块1. Distributor(分发器端)2. CPU Interface(CPU 接口端) 五、CP15 协处理器六、中断使能1. IRQ 和 FIQ 总中断使能2. ID0~ID1019 中断使能和禁止 七、中断…

【PXE高效的批量网络装机】

目录 一、PXE的概述1.1、PXE批量部署的优点1.2、搭建PXE满足的以下的前提条件1.3、搭建PXE远程安装 二、搭建PXE远程安装服务器1、安装并启动 TFTP 服务2、安装并启用 DHCP 服务3、准备 Linux 内核、初始化镜像文件4、准备PXE 引导程序5、安装FTP服务&#xff0c;准备CentOS 7 …

SpringMVC使用域对象共享数据

1、SpringMVC中的域对象 此处只有request、session、servletContext被使用&#xff0c;而page是jsp页面的域&#xff0c;不使用jsp。 request&#xff1a;一次请求的范围内session&#xff1a;一次会话的范围内servletContext&#xff1a;整个web的应用范围内 2、向request域…

MySQL高级第十七篇:数据库主从复制原理及保证数据一致性

MySQL高级第十七篇&#xff1a;数据库主从复制原理及保证数据一致性 一、概述1. 提升数据库的并发能力2. 主从复制的作用&#xff1f; 二、主从复制原理三、搭建一主一从环境四、如何解决数据一致性问题&#xff1f;1. 方案一、异步复制2. 方案二、半同步复制3. 方案三、组复制…

3.黑马Springboot原理篇自己修改笔记

原理篇 1.自动配置的工作流程 1.1 bean的加载方式 方式一&#xff1a;配置文件<bean/>标签 缺点&#xff1a;配置bean太繁琐 方式二&#xff1a;配置文件扫描注解定义bean⭐️ 获取bean方式 ①通过配置文件&#xff0c;扫描指定包&#xff0c;加载bean ②通过注解声…