python 之 装饰器(Decorators)

装饰器本质上也是一个函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,可以接受一个函数作为参数,并返回一个新的函数。

1. 装饰器的定义

装饰器的基本语法是使用@符号,后面跟着装饰器的名称。这个符号应该放在函数定义的上方。

2. 装饰器的示例代码

装饰器代码示例:

def my_decorator(func):  def wrapper():  print("Before function call")  func()  print("After function call")  return wrapper  @my_decorator  
def say_hello():  print("Hello!")  say_hello()

在这个例子中,my_decorator是一个装饰器。当它被应用到say_hello函数上时,它会返回一个新的函数wrapper。这个新的函数在调用原始函数say_hello之前和之后都打印一条消息。因此,当你调用say_hello()时,实际上是在调用wrapper()函数,它会首先打印"Before function call",然后调用say_hello()打印"Hello!“,最后打印"After function call”。

3. 常见的装饰器用法

  • 日志记录:装饰器可以用来在函数执行前后添加日志记录。这有助于跟踪函数的调用情况,以及在出现问题时进行调试。
import logging  def log_decorator(func):  def wrapper(*args, **kwargs):  logging.info(f"Calling {func.__name__} with args: {args} and kwargs: {kwargs}")  result = func(*args, **kwargs)  logging.info(f"{func.__name__} returned: {result}")  return result  return wrapper  @log_decorator  
def add_numbers(a, b):  return a + b  # 测试  
add_numbers(3, 4)
  • 性能分析:通过装饰器,你可以测量函数的执行时间,从而分析代码的性能。这对于优化性能瓶颈非常有用。
import time  def timing_decorator(func):  def wrapper(*args, **kwargs):  start_time = time.time()  result = func(*args, **kwargs)  end_time = time.time()  print(f"Function {func.__name__} took {end_time - start_time:.6f} seconds to execute.")  return result  return wrapper  @timing_decorator  
def slow_function():  time.sleep(1)  # 模拟耗时操作  # 测试  
slow_function()
  • 权限检查:装饰器可以用于实现权限检查,确保只有具有特定权限的用户才能调用特定的函数或方法。
def permission_decorator(func):  def wrapper(*args, **kwargs):  if not has_permission():  # 假设这是检查权限的函数  print("Permission denied!")  return None  return func(*args, **kwargs)  return wrapper  def has_permission():  # 这里应该是检查用户权限的逻辑  # 返回True表示有权限,返回False表示无权限  return True  # 示例中直接返回True,实际中需要根据用户或环境判断  @permission_decorator  
def sensitive_operation():  print("Executing sensitive operation...")  # 测试  
sensitive_operation()
  • 缓存结果:对于计算成本较高的函数,可以使用装饰器来缓存其结果,以便在后续调用时直接返回缓存的结果,从而提高效率。
def cache_decorator(func):  cache = {}  def wrapper(*args):  if args in cache:  return cache[args]  result = func(*args)  cache[args] = result  return result  return wrapper  @cache_decorator  
def fibonacci(n):  if n <= 1:  return n  return fibonacci(n-1) + fibonacci(n-2)  # 测试  
print(fibonacci(10))  # 第一次计算,结果会被缓存  
print(fibonacci(10))  # 第二次计算,直接从缓存中获取结果,不会重新计算
  • 函数注册:装饰器可以用于自动注册函数到某个注册表或容器中,方便后续的管理和调用。

  • 函数参数校验:装饰器可以在函数调用前对参数进行校验,确保传入的参数符合预期,从而避免在函数内部进行繁琐的参数检查。

  • 事务管理:对于需要数据库操作的函数,装饰器可以用来实现事务管理,确保在出现异常时能够回滚事务,保持数据的一致性。

  • 异常处理:装饰器可以用来统一处理函数抛出的异常,例如记录异常信息、发送报警邮件等。

  • 函数替换或增强:装饰器可以在不修改原始函数代码的情况下,替换或增强函数的功能。这对于扩展现有库或框架的功能非常有用。

4. pytest 框架中装饰器的用法

  • 组织测试用例:装饰器可以帮助你根据特定的条件或属性对测试用例进行分组或标记。例如,你可以使用@pytest.mark.skipif装饰器来跳过某些特定条件下不应该运行的测试用例。同样,你可以使用@pytest.mark.xfail来标记预期失败的测试用例。

  • 参数化测试:pytest提供了@pytest.mark.parametrize装饰器,允许你为测试函数提供多组参数和预期结果,从而执行参数化测试。这可以极大地减少冗余代码,并提高测试覆盖率。

  • 依赖管理和测试顺序:虽然pytest默认不保证测试函数的执行顺序,但你可以使用装饰器(结合其他机制)来管理测试之间的依赖关系。例如,你可以使用pytest-ordering插件和相应的装饰器来指定测试的执行顺序。

  • 自定义钩子:pytest具有一个强大的插件系统,允许你通过编写自定义插件来扩展其功能。在这些插件中,你可以定义自己的装饰器来实现特定的测试逻辑或行为。

  • 简化复杂逻辑:对于需要在多个测试用例中重复使用的复杂逻辑,你可以将其封装在装饰器中,从而减少测试代码的冗余。这使得测试用例更加简洁和易于维护。

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

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

相关文章

leetcode 494.目标和

思路&#xff1a;可以转化为背包问题。 首先我们看到&#xff0c;题目中要求我们求出目标数的方案数。既然有正数也有负数&#xff0c;那么就一定会从数组中选一部分当负数&#xff0c;选一部分当正数。 假如我们拿z当作选取当正数的元素的和&#xff0c;sum当作全部元素之和…

十、C#基数排序算法

简介 基数排序是一种非比较性排序算法&#xff0c;它通过将待排序的数据拆分成多个数字位进行排序。 实现原理 首先找出待排序数组中的最大值&#xff0c;并确定排序的位数。 从最低位&#xff08;个位&#xff09;开始&#xff0c;按照个位数的大小进行桶排序&#xff0c;将…

06 分页

文章目录 PageInfo PageInfo package com.aistart.tech.common;import java.io.Serializable; import java.util.List;public class PageInfo<T> implements Serializable {private Integer pageNum;//当前页private Integer pageSize;//每页显示条数private Integer pa…

将OpenCV与gdb驱动的IDE结合使用

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV4.9.0开源计算机视觉库在 Linux 中安装 下一篇&#xff1a;将OpenCV与gcc和CMake结合使用 ​ 能力 这个漂亮的打印机可以显示元素类型、、标志is_continuous和is_subm…

ClickHouse的表操作

1、背景 由于大数据平台需要对数据进行分析,因为ClickHouse是一个开源的列式数据库管理系统(DBMS)&#xff0c;专为联机分析处理(OLAP)而设计。 官方地址&#xff1a;ClickHouse 开发 | ClickHouse Docs 2、集群中的操作 在操作集群中的表的时候&#xff0c;最好是采用[dbn…

【设计模式】Java 设计模式之状态模式(State)

深入理解状态模式&#xff08;State&#xff09; 一、概述 状态模式是一种行为设计模式&#xff0c;它允许一个对象在其内部状态改变时改变它的行为。对象看起来好像修改了它的类。状态模式把所有的与一个特定的状态相关的行为放到一个类中&#xff0c;并且将请求委托给当前状…

5.79 BCC工具之tcpaccept.py解读

一,工具简介 tcpaccept工具用于追踪接受TCP套接字连接的内核函数(例如,通过accept()函数实现的被动连接;不是connect()函数)。 accept() 是一个在 UNIX-like 系统上用于套接字编程的系统调用,它在 TCP 服务器中起着关键作用。当 TCP 服务器通过 listen() 系统调用使其套…

蓝桥杯 全球变暖

Problem: 蓝桥杯 全球变暖 文章目录 思路解题方法复杂度Code 思路 这道题目可以使用深度优先搜索&#xff08;DFS&#xff09;或广度优先搜索&#xff08;BFS&#xff09;来解决。我们需要遍历整个地图&#xff0c;当遇到陆地&#xff08;‘#’&#xff09;时&#xff0c;就进行…

分块算法模板更新

基础模板&#xff08;区间修改&#xff0c;求区间和&#xff09; #include "bits/stdc.h" using namespace std; #define int long long const int N 100010;int sum[N],add[N],a[N],b[N]; int l[N],r[N];void change(int l1,int r1,int k) {int pb[l1],qb[r1];if(…

【Java常用API】简单爬虫练习题

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

0基础学习VR全景平台篇第146篇:为什么需要3D元宇宙编辑器?

一.什么是3D元宇宙编辑器&#xff1f; 3D元宇宙编辑器是全新3DVR交互渲染创作工具&#xff0c;集3D建模、虚拟展厅、AI数字人等能力&#xff0c;渲染和虚拟现实技术于一身的生产力工具。 具有跨平台和随时随地编辑等特点&#xff0c;可广泛应用于展会、展厅、博物馆、可视化园…

uniapp_微信小程序客服

一、调用api 二、代码 <button open-type"contact">客服</button> 三、小程序后台添加客服人员就行

Ubuntu学习笔记之Shell与APT下载工具

基本都是摘抄正点原子的文章&#xff1a;<领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf&#xff0c;因初次学习&#xff0c;仅作学习摘录之用&#xff0c;有不懂之处后续会继续更新~ 一、Ubuntu Shell操作 简单的说Shell 就是敲命令。国内把 Linux 下通过命令行输入命令叫…

RabbitMQ docker 单机部署

RabbitMQ docker 单机部署 1.单机部署 我们在Centos7虚拟机中使用Docker来安装。 1.1.下载镜像 方式一&#xff1a;在线拉取 docker pull rabbitmq:3.8-management1.2.安装MQ 执行下面的命令来运行MQ容器&#xff1a; docker run \-e RABBITMQ_DEFAULT_USERroot \-e RAB…

CSS隐藏video标签中各种控件

1.edio标签加上controls会出现视频控件&#xff0c;如播放按钮、进度条、全屏、观看的当前时间、剩余时间、音量按钮、音量的控制条等等 <video type"video/mp4" src"" autoplay"" style"width: 400px; height: 300px;" id"e…

idea 2023 spring initializr 没有JDK1.8选项的解决方法

在升级最新版本的IDEA后,新建项目里面的 spring initializr的选项里面已经没有了JDK1.8的选项了,原因是spring官方的initializr https://start.spring.io/ 现在主推3.x版本这个最低要求是JDK17, 解决方法: 将IDEA默认的 Initializr的URL https://start.spring.io/换成第三方…

3/21 work

自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面。&#xff08;不要使用课堂上的图片和代码&#xff0c;自己发挥&#xff0c;有利于后面项目的完成&#xff09; 要求&#xff1a; 1. 需要使用Ui界面文件进行界面设计 2. ui界面上的组件相关设置&#xff0c;通…

记一次 .NET某游戏后端API服务 CPU爆高分析

一&#xff1a;背景 1. 讲故事 前几天有位朋友找到我&#xff0c;说他们的API服务程序跑着跑着CPU满了降不下去&#xff0c;让我帮忙看下怎么回事&#xff0c;现在貌似民间只有我一个人专注dump分析&#xff0c;还是申明一下我dump分析是免费的&#xff0c;如果想学习.NET高级…

CDH中重装Kafka

##事情缘由 之前测试集群kafka安装在01、02、04节点&#xff0c;但是01节点经常宕机&#xff0c;于是直接在CM页面上把01节点上的kafka broker手动删除了。。。 然后重新再03节点安装了新的kafka broker 于是kafka集群不能使用了&#xff01;&#xff01;&#xff01; ##初始化…

Springboot中Tomcat配置及切换Undertow

一、Tomcat配置 1. 通过application.yml配置 以下展示常用配置 server:port: 8182 # 配置端口tomcat:threads:max: 10 # 最大工作线程&#xff0c;默认是200min-spare: 5 # 最小工作线程&#xff0c;默认是10accept-count: 200 # tomcat启动线程达到最大值后&#xff0c;接受…