Python装饰器笔试题(简单难度)

文章目录

  • 前言
  • 用函数调用函数
  • 用函数返回函数
  • 用函数返回包装函数
  • 使用@
  • 再进一步
  • 应用场景

前言

这次遇到了一个比较神奇的面试题:给定方法

def add(x, y):return x + y

要求在不改变源代码的前提下,使用装饰器,为add方法增加运行时间输出的功能。

用函数调用函数

其实本身而言并没有什么特别难的内容,只是单纯的比较综合罢了。

首先,我们尝试一下函数包函数,也就是说,我们将add函数包装为其他的函数:

import time
def decorate_add(x, y):start = time.time()def add(x, y):return x + yresult = add(x, y)end = time.time()time_consumption = end - startprint(result, time_consumption)

看起来没什么问题,连输出也不需要说明,一目了然。但是呢,这样会不会太简单了?我们先升级一下难度。

用函数返回函数

没错,函数返回函数,然后调用函数,就能够获得结果。就像这样:

import timedef time_consume_f(f):start = time.time()print(f())end = time.time()print(end - start)return time_consume_fdef add():return 1e3decorater = time_consume_f(add)
decorater(add)

输出结果就会是

1000.0

0.0

1000.0

0.0

没错,因为f本身具有print功能,在调用decorater的时候又调用了一遍。

当然,你也看到,这样的方法没办法继续输入参数了。得再想想办法。

用函数返回包装函数

既然我们单纯的用一层函数包装不够,我们使用两层呢?外层先传入函数,内层使用相同的参数,并调用外层传入的函数,是不是就能解决问题呢?

试试看:

import time
def decorater(func):def wrapped(*args, **kwargs):start = time.time()result = func(*args, **kwargs)end = time.time()print('time: ', end - start)return resultreturn wrappeddef add(x, y):return x + ywrapped_function = decorater(add)
wrapped_function(1, 2)

输出:

0.0

3

这下是我们想要的结果了。

使用@

如果你使用Flask,你会想到你曾经在一些controller方法上增加一个@app.route('/api'),让前端从http://localhost:8080/api中访问到你的方法。

那么,现在我们应该如何使用呢?

其实并不需要做出太多改动:

import time
def decorater(func):def wrapped(*args, **kwargs):start = time.time()result = func(*args, **kwargs)end = time.time()print('time: ', end - start)return resultreturn wrapped@decorater
def add(x, y):return x + yadd(1, 2)

输出还是老样子:

0.0

3

看来@只是一个简写。

再进一步

其实到此为止已经足够了。但是既然官方都有,那我们就用一下吧。

import time
from functools import wrapsdef time_consume(f):@wraps(f)def wrapTheFunction(*args, **kargs):start = time.time()result = f(*args, **kargs)end = time.time()print(end - start)return resultreturn wrapTheFunction@time_consume
def add(x, y):return x + yprint(add(1, 2))

其实效果是完全相同的:

0.0

3

但是呢,@wraps的作用主要就是装饰一个函数,并赋值函数名称、注释文档、参数列表等等

接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。总之就是,比我们单纯用双层函数功能全多了。

应用场景

当然,我们现在只考虑了两层嵌套的用法,也就是对一个函数进行包装,从而无侵入地使得这个函数拥有更多的功能。

而如果我再嵌套一层呢?没错,还能继续接收参数。

这也就是Flask@app.route()中能够有那么多参数的真正原因。我们通过这样的三层嵌套实现相对较为统一的、相对比较重复的内容,从而让我们在实现业务的过程中能够更专注于业务,剩下的装饰一下就好了。

我们举个例子吧。比如,我需要将日志保存在指定的文件中,但是我又不希望在代码中植入日志编辑的逻辑,因为这样只会让代码更为复杂。那么该怎么办呢?当然就是使用装饰器,通过截取函数中的所有print内容,然后再将这些内容写入文件。

我们可以首先定义一个三层嵌套的装饰器:

import sys
from contextlib import redirect_stdout
from io import StringIOdef redirect_print_to_log(log_path="app.log"):def decorator(func):def wrapper(*args, **kwargs):# 创建一个字符串流用于捕获print输出temp_stdout = StringIO()# 保存原始的sys.stdoutoriginal_stdout = sys.stdouttry:# 重定向标准输出到字符串流with redirect_stdout(temp_stdout):result = func(*args, **kwargs)# 将捕获的输出追加到指定的日志文件中with open(log_path, "w", encoding='utf-8') as log_file:log_file.write(temp_stdout.getvalue())finally:# 恢复原始的sys.stdoutsys.stdout = original_stdoutreturn resultreturn wrapperreturn decorator

当然,你也可以使用@wraps装饰器,这里就不再赘述了。这里实际上就是在双层嵌套的基础上再加一层嵌套,使得装饰器可以接收参数,就像这样:

@redirect_print_to_log("your_file.log")
def your_function(*args, **kwargs):print("your print")

在这段代码中,装饰器接收的参数就是log_path,即日志文件的路径your_file.log。这样就能够截取your_function中所有的print输出(这里就是截取到了your print),然后将这些输出写入到your_file.log中。

最后,打开your_file.log,文件中就存在your print字样了。

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

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

相关文章

k8s集群的CA证书过期处理

文章目录 制作延期的CA证书获取CA全名准备签发申请配置生成新CA验证并替换CA 更新master组件的CA配置kube-apiserverkube-controller-managerkube-schedulerkube-admin检查证书过期时间 更新ServiceAccount secret更新node组件配置的CA更新kubelet连接配置签发kubelet自动申请的…

Google Play上架:自查封号政策解析(高风险行为之不允许破坏Google Play生态系统中用户信任度的应用或应用内容)

本文章提供给近期被封号的开发者们,希望能带来帮助,有其他的自查方向后续也会发布出来。 ——————————————————————————————————————— 用户数据设备和网络滥用 用户数据 设备和网络滥用

redis 缓存击穿问题(互斥锁,逻辑过期)

1、缓存击穿问题 缓存击穿问题:一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。 场景:假设线程1在查询缓存之后,本来应该去查询数据库,然后把这个数据重新加…

堆以及堆的实现

文章目录 堆的概念堆的实现HeapPushHeapPop HeapTop HeapSize HeapEmpty堆的应用 堆的概念 堆是一颗完全二叉树每个结点的值都小于子结点的值,这颗二叉树为小根堆每个结点的值都大于子结点的值,这颗二叉树为大根堆堆的定义如下:n个元素的序列…

开展庆2024年“三八”国际妇女节系列纪念活动怎样向媒体投稿?

为了向媒体投稿,庆祝2024年“三八”国际妇女节系列纪念活动,你可以遵循以下步骤: 策划与准备: 确定纪念活动的主题和目标,例如提升女性权益、表彰女性成就、促进性别平等。 策划一系列活动,如研讨会、表彰仪式、展览、讲座等,确保内容丰富多样。 准备相关的背景资料、活动介…

Linux Watchdog 机制是什么

当涉及到Linux操作系统的稳定性和可靠性时,Linux Watchdog机制是一个至关重要的议题。该机制旨在监控系统状态,确保在出现问题时采取适当的措施以维持系统的正常运行。本文将深入探讨Linux Watchdog机制的工作原理、应用范围以及如何配置和使用该机制来提…

WebGIS开发0基础必看教程:WebGIS中的要素(Feature)

1.前言 在GIS中元素一般分为点元素,线元素,面元素以及symbol元素(特殊的点元素)等。与此对应,图层可以分为点图层,线图层,面图层以及标注图层等。从第9章到第10章,我给大家讲解了什…

黑豹程序员-vue3下载时显示下载的百分比

原理 axios 有一个方法&#xff1a;onDownloadProgress&#xff0c;它可以实时返回e.loaded 已经加载的值和e.total总数&#xff0c; Math.round(e.loaded / e.total * 100) 通过计算刚好获取到已经处理的百分比。 实现代码 <template><div><button click&qu…

力扣大厂热门面试算法题 - 动态规划

爬梯子、跳跃游戏、最小路径和、杨辉三角、接雨水。每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.05 可通过leetcode所有测试用例。 目录 70. 爬楼梯 解题思路 完整代码 Python Java 55. 跳跃游戏 解题思路 完整代码 Python 代码…

kafka高水位和leader epoch

什么是高水位&#xff1f; 高水位表示分区下副本消息到哪里是算正常提交的。比如如下图&#xff1a;leader副本写到8了&#xff0c;follower副本也写到8&#xff0c;那么这个8就代表要求的副本都写入了。消息到8这里才算提交成功&#xff0c;后面的15写入了也不算提交成功&…

【Leetcode 2673】使二叉树所有路径值相等的最小代价 —— 贪心法

2673. 使二叉树所有路径值相等的最小代价 给你一个整数n表示一棵 满二叉树 里面节点的数目&#xff0c;节点编号从1到n。根节点编号为1&#xff0c;树中每个非叶子节点i都有两个孩子&#xff0c;分别是左孩子2 * i和右孩子2 * i 1。 树中每个节点都有一个值&#xff0c;用下…

Vscode C/C++ 编译问题

1.最近开始在VScode上编写程序&#xff0c;遇到了以下的坑 This may occur if the process’s executable was changed after the process wasstarted, such as when installing an update. Try re-launching the application orrestarting the machine. 2.原因 这个不是由vs…

Java开发工程师面试题(JVM)

一、JVM调优常用命令和常用参数&#xff1a; 常用命令 jps&#xff1a;查看进程及其相关的信息。jmap&#xff1a;用来生成dump文件和查看堆相关的各类信息的命令。jstat&#xff1a;查看JVM运行时的状态信息。&#xff08;如jstat -gcutil可以查看gc发生的频率和次数&#x…

技术上的判断令你如何确定现货黄金卖出时机?

要讨论现货黄金卖出时机&#xff0c;我们首先要搞清楚一个问题&#xff0c;就是开仓和平仓的问题&#xff0c;如果投资者已经成了市场中的多头&#xff0c;那他寻找的卖出时机就是要找多头平仓的时机&#xff0c;如果投资者还没开仓&#xff0c;正在寻找市场中的开仓机会&#…

【RS】最新欧空局Sentinel-2卫星数据下载(哨兵1、2、3、5P、6系列)

之前分享过Sentinel2数据下载的方法&#xff0c;但是有粉丝反应欧空局的网站更新了&#xff0c;之前的网站已经不能用了。所以自己抽空研究了一下新版的欧空局网站&#xff0c;今天就和大家分享一下如何使用新版的欧空局网站下载哨兵系列的卫星数据&#xff0c;本文以Sentinel2…

c语言-大小写字母的转换

目录 方法一&#xff1a;库函数直接转换 1、toupper的测试代码 2、tolower的测试代码 方法二&#xff1a;通过修改ASCII码值转换 1、自己实现大写转小写 2、自己实现小写转大写 结语 前言&#xff1a; 在使用c语言写代码时&#xff0c;通常会遇到很多将大小写字母相互…

IP定位在公安部门的使用及其重要性

随着信息技术的迅猛发展&#xff0c;互联网已成为现代社会不可或缺的一部分。然而&#xff0c;与此同时&#xff0c;网络犯罪也呈现出日益猖獗的趋势&#xff0c;给社会治安带来了极大的挑战。在这样的背景下&#xff0c;IP定位技术在公安部门的应用显得尤为重要。本文将对IP定…

geoserver+mapbox-gl 离线部署矢量切片地图服务学习笔记

geoserver安装 geoserver的安装包可以在官网下载Download - GeoServer&#xff0c;想要选择版本点击Archived找到指定版本进行下载http://geoserver.org/download/ &#xff08;如果网络不稳定&#xff0c;也可以直接使用下面的下载地址&#xff09; geoserver-2.15.0.rar资…

手把手带你申请【Sora】内测资格,附申请提示词

自从OpenAI发布了Sora之后&#xff0c;由于其流畅的画面&#xff0c;极高的真实度的60秒超长视频&#xff0c;瞬间秒杀当前市面上所有的视频胜场模型。 附上体验地址&#xff1a;https://openai.com/research/video-generation-models-as-world-simulators 相信Sora发布之后也…

PRewrite: Prompt Rewriting with Reinforcement Learning

PRewrite: Prompt Rewriting with Reinforcement Learning 基本信息 2024-01谷歌团队提交到arXiv 博客贡献人 徐宁 作者 Weize Kong&#xff0c;Spurthi Amba Hombaiah&#xff0c;Mingyang Zhang 摘要 工程化的启发式编写对于LLM&#xff08;大型语言模型&#xff09;应…