Python进阶--装饰器

装饰器简介

每个Python开发者早晚都会遇到装饰器@,装饰器通常用于增强函数功能。
例如,在Django中用装饰器为视图添加权限:

@permission_required('edit_publisher')
def publisher_edit(request, pk=None):...

注册标签

@register.simple_tag
def generic_simple_tag(arg1, arg2):...

装饰器是可调用对象,其参数是一个函数。返回值是一个函数。
下面我们定义一个装饰器dec,它的作用是在执行函数前打印一句话"做了一个装饰"。

def dec(func):def inner():print("做了一个装饰")func()return inner

可以用两种方式使用装饰器

  1. @dec放在函数定义上面一行。(常用)
  2. 将函数传递给装饰器dec(func2)
@dec
def func1():print("Hello! func1")def func2():print("Hello! func2")func1()
print("---")
dec_func2 = dec(func2)
print("---")
dec_func2() 

输出:

做了一个装饰
Hello! func1
---
---
做了一个装饰
Hello! func2

实用的装饰器

1. 计时器

下面定义了一个记录函数耗时的装饰器。

import time
import functools
def clock(func):@functools.wraps(func)def clocked(*args, **kwargs):t0 = time.perf_counter()result = func(*args, **kwargs)elapsed = time.perf_counter() - t0name = func.__name__arg_lst = [repr(arg) for arg in args]arg_lst.extend(f'{k}={v!r}' for k, v in kwargs.items())arg_str = ', '.join(arg_lst)print(f'[{elapsed:0.8f}s] {name}({arg_str}) -> {result!r}')return resultreturn clocked@clock
def factorial(n):return 1 if n < 2 else n*factorial(n-1)factorial(3)

运行结果:

[0.00000030s] factorial(1) -> 1
[0.00004380s] factorial(2) -> 2
[0.00005380s] factorial(3) -> 6

clocked在执行函数前后各记录一次时间,得到函数运行耗时,并且打印函数名称和参数。
clocked函数使用@functools.wraps(func)修饰,@wraps的作用是将所有元数据从一个函数复制到另一个函数,这样可以保留原始函数的信息。(*args, **kwargs)实现了可变数量的位置参数、关键字参数。

2. 返回装饰器的函数

返回装饰器的函数可以实现更灵活的装饰器。
下面定义了一个返回装饰器的函数。装饰器的作用是:当upper_case=True时将func的返回字符串转化成大写,否则返回原始字符串。

from functools import wraps
def function_that_creates_a_decorator(upper_case=False):def decorator(func):@wraps(func)def wrapper(*args, **kwargs):result = func(*args, **kwargs)if upper_case: result = result.upper()return resultreturn wrapperreturn decorator

这个代码看起来有点奇怪,我们一层层地读一下。

  • 最外层定义了一个函数def function_that_creates_a_decorator(upper_case=False),这个函数的作用是返回一个装饰器。
  • 第二层的def decorator(func)是真正的装饰器,返回包装后的函数。
  • 第三层的def wrapper(*args, **kwargs)是包装的函数。这个函数使用@wraps修饰。
@function_that_creates_a_decorator(upper_case=True)
def normalize_user_input(user_input: str, default: str | None=None) -> str | None:"""Reduce PBCK as much as possible"""return str(user_input).strip().casefold() or defaultresult = normalize_user_input("HEllo, WoRLD")
print(result)

运行结果:

HELLO, WORLD

注意@function_that_creates_a_decorator(upper_case=True)使用了(),是一个函数调用,返回了装饰器。

装饰器的注意事项

  1. 装饰器在导入模块时立即执行,而被装饰的函数只在显式调用时运行。
  2. 可以使用多个装饰器,装饰器将按照从里到外的顺序进行装饰。如:
def dec1(func):def inner():print("做了一个装饰dec1")func()return innerdef dec2(func):def inner():print("做了一个装饰dec2")func()return inner@dec2 
@dec1
def func1():print("Hello! func1")func1()

运行结果:

做了一个装饰dec2
做了一个装饰dec1
Hello! func1

参考&推荐阅读

  1. 《流畅的Python》(第二版) 第9章 装饰器和闭包
  2. https://www.bitecode.dev/p/xmas-decoration-part-2

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

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

相关文章

C++大学教程(第九版)7.30 打印array对象 7.31 逆序打印字符串(递归练习题)

文章目录 题目代码运行截图题目代码运行截图 题目 (打印array对象)编写一个递归函数printArray它以一个array对象一个开始下标和一个结束下标作为实参&#xff0c;不返回任何值并打印这个array对象。当开始下标和结束下标相等时&#xff0c;这个函数应该停止处理并返回。 代码…

跨镜网络解决方案:SD-WAN专线,实现企业全球互联

在全球化的背景下&#xff0c;越来越多的企业需要在海外社媒平台推广、研发访问海外平台、实现海外分部和国内互联互通等需求。然而&#xff0c;面对不同地区之间网络连接不稳定、高延迟、高成本等问题&#xff0c;如何实现企业的全球互联成为了一个亟待解决的难题。 幸运的是&…

laravel学习笔记

这两天公司活不多&#xff0c;学习了一下laravel框架。经过几天的学习&#xff0c;也对它有一些大概的了解。现在我就把我所学的到在这儿做下笔记吧。 一、laravel集合 其实&#xff0c;这里所说的集合&#xff0c;跟前端es6中的集合概念还是有那一点的不太一样。前端es6的集合…

小世界网络 | 小世界网络(Python)

概述 小世界网络是一种网络模型,用于描述网络中节点之间的连接方式。它是基于"六度分隔理论"提出的,该理论认为任意两个人之间的联系最多通过六个中间人来实现。小世界网络模型试图解释人际关系网络、社交网络以及其他一些网络结构的特点。 在小世界网络中,节点…

C++ 数论相关题目:卡特兰数应用、快速幂求组合数。满足条件的01序列

给定 n 个 0 和 n 个 1 &#xff0c;它们将按照某种顺序排成长度为 2n 的序列&#xff0c;求它们能排列成的所有序列中&#xff0c;能够满足任意前缀序列中 0 的个数都不少于 1 的个数的序列有多少个。 输出的答案对 1097 取模。 输入格式 共一行&#xff0c;包含整数 n 。 …

Java 集合 02 综合练习+基本数据类型对应的包装类

练习1、 自己写的代码&#xff1a; import java.util.ArrayList; public class practice {public static void main(String[] args) {//定义一个集合ArrayList<String> list new ArrayList<>();list.add("aaa");list.add("bbb");list.add(…

理解C++中类内静态函数在类外定义时为何不需再加static关键字

理解C中类内静态函数在类外定义时为何不需再加static关键字 在C中&#xff0c;静态成员函数是类的成员函数&#xff0c;它们与类的实例无关&#xff0c;而是与整个类相关联的。当我们在类内部声明静态成员函数时&#xff0c;我们使用关键字 static 来标识它们。然而&#xff0…

Dockerr开发环境搭建

Docker安装 sudo apt install docker.ioDocker运行权限 #添加docker group sudo groupadd docker# 将当前用户添加到docker组 sudo gpasswd -a ${USER} docker# 重启docker服务&#xff1a; sudo service docker restart# 查看用户组及成员&#xff1a; cat /etc/group | gr…

python实现豆瓣电影搜索并自动添加相关信息

1.豆瓣电影搜索 2.豆瓣电影信息自动添加 搜索 众所周知&#xff0c;豆瓣搜索有加密&#xff0c;得解密才行&#xff0c;还好网上众多大神都给破解了&#xff0c;那咱们拿来直接使用就行 相关代码仓库&#xff1a;xadmin-server/movies/utils/douban/search.py at movies nin…

React中使用LazyBuilder实现页面懒加载方法一

前言&#xff1a; 在一个表格中&#xff0c;需要展示100条数据&#xff0c;当每条数据里面需要承载的内容很多&#xff0c;需要渲染的元素也很多的时候&#xff0c;容易造成页面加载的速度很慢&#xff0c;不能给用户提供很好的体验时&#xff0c;懒加载是优化页面加载速度的方…

Vue视频图片的在线存储仓库【七牛云】的使用

文章目录 概要引入七牛云的依赖配置七牛云七牛云的使用小结 概要 七牛云的使用 官网&#xff1a;点击跳转 引入七牛云的依赖 npm install qiniu-js配置七牛云 import Vant from vant; Vue.prototype.$qiniu qiniu七牛云的使用 const that this//七牛云配置项②const obse…

汽车加油问题

汽车加油问题 Description 一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法&#xff0c;指出应在哪些加油站停靠加油&#xff0c;使沿途加油次数最少。并证明算法能产生一个最优解。 对于给定的n和k个加油站位置&#xff0c;计算最少加油次数。 Input …

AJAX进阶(重点)

目录 ◆ 同步代码和异步代码 ◆ 回调函数地狱和 Promise 链式调用 什么是回调函数地狱&#xff1f; Promise - 链式调用 什么是Promise链式调用&#xff1f; Promise 链式应用 &#xff08;重点&#xff09; ◆ async 和 await 使用 async函数和await_捕获错误 ◆ 事…

二分查找|详细讲解|两种写法

二分查找 目录 1 介绍2 例题引入3 “左闭右闭”写法4 “左闭右开”写法 1 介绍 二分查找适用于从一个递增或递减的有序数列中查找某一个值 因此&#xff0c;使用二分查找的条件是&#xff1a; 用于查找的内容从逻辑上来看是有序的查找的数量只能是一个而不是多个 在二分查…

RAG应用-七个最常见的故障点

近日&#xff0c;国外研究者发布了一篇论文《Seven Failure Points When Engineering a Retrieval Augmented Generation System》&#xff0c;探讨了在实际工程落地RAG应用过程中容易出的七类问题。 论文地址&#xff1a;https://arxiv.org/pdf/2401.05856.pdf 一、丢失内容&…

【Go-zero】手把手带你在goland中创建api文件并设置高亮

【Go-zero】手把手带你在goland中创建api文件并设置高亮 大家好 我是寸铁&#x1f44a; 总结了一篇手把手带你在goland中创建api文件并设置高亮解决方案的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 问题复盘 在使用go-zero 框架时&#xff0c;常常需要用到goctl 一键生成…

简单易用的购物车

实现了购物基本功能&#xff0c;那来修改一下就可以用&#xff0c;app,h5,小程序都可以 购物车插件 - DCloud 插件市场

会话技术复习笔记

一.登录校验的需求 什么是登录校验&#xff1f; 所谓登录校验&#xff0c;指的是我们在服务器端接收到浏览器发送过来的请求之后&#xff0c;首先我们要对请求进行校验。先要校验一下用户登录了没有&#xff0c;如果用户已经登录了&#xff0c;就直接执行对应的业务操作就可以…

数据结构——用Java实现二分搜索树

目录 一、树 二、二分搜索树 1.二叉树 2.二分搜索树 三、代码实现 1.树的构建 2.获取树中结点的个数 3.添加元素 4.查找元素 &#xff08;1&#xff09;查找元素是否存在 &#xff08;2&#xff09;查找最小元素 &#xff08;3&#xff09;查找最大元素 5.二分搜索…

合并有序链表---链表OJ---归并思想

https://leetcode.cn/problems/merge-two-sorted-lists/?envTypestudy-plan-v2&envIdtop-100-liked 将两个有序的链表合并为一个新的有序链表&#xff0c;那不就是和归并排序中最后合并的思想一样吗&#xff1f;只不过那里合并的是数组&#xff0c;这里合并的是链表。 首先…