python重写和装饰器_python装饰器

python装饰器的本质,就是闭包!

我们一般谈Python的闭包,都是指普通的入参,而谈装饰器的时候,入参一定有函数!闭包和装饰器,返回的都是函数。函数是代码的最小封装单位,装饰器作用于函数,它不影响函数自身的执行,只是在函数的执行前后增加一些“装饰性”的动作。装饰器被称为python的语法糖(syntax sugar),也被视为python支持AOP编程(面向切面编程)的工具。

简单装饰器

以下代码实现了一个最简单的额装饰器,功能是给带上装饰器的函数,在函数执行前,增加一行print打印,代码如下:

test1函数加上了calling_trace装饰器,在第7行,这一行代码的作用,相同于第11行的注释。test1还是test1,这个名字没有变,只是换成了一个闭包函数的返回值,此闭包函数,就是装饰器,它接收一个函数作为参数。以上代码运行效果如下:

$ python3 deco.py

calling test1

test1 is runing...

我们还可以稍微复杂一点点,既然是装饰器,被装饰的函数执行前后都可以加点小动作。修改后的代码如下:

def calling_trace(func):

def wrapper():

print('calling', func.__name__)

a = func()

print('this is the reture:',a)

return wrapper

@calling_trace

def test2():

print('test2 is runing...')

return 'www.pynote.net'

# test2 = calling_trace(test2)

test2()

新的装饰器没有改名字,只是获取了被装饰函数的返回值,并将返回值打印出来。运行效果如下:

$ python3 deco.py

calling test2

test2 is runing...

this is the reture: www.pynote.net

test2函数执行前后,都增加了一些动作,作为装饰!

这就是装饰器的概念:不修改已有函数的代码,也不修改已有函数的调用处代码,却达到了丰富函数功能的效果!本质上装饰器是对函数的一种封装,只是我们要理解@语法。

闭包和装饰器

装饰器的本质就是闭包,我们如果把上面这段代码重写一遍,采用闭包的语法形式,不使用@语法,效果是完全一样的:

def calling_trace(func):

def wrapper():

print('calling', func.__name__)

a = func()

print('this is the reture:',a)

return wrapper

def test2():

print('test2 is runing...')

return 'www.pynote.net'

t = calling_trace(test2)

t()

以上代码,没有@语法的使用啦,用变量t来获取calling_trace返回的函数对象,然后调用,效果与使用装饰器完全一样:

$ python3 deco.py

calling test2

test2 is runing...

this is the reture: www.pynote.net

使用@语法,阅读代码就如吃糖!

装饰带参数的函数

如果被装饰的函数有参数,需要在装饰器内部原样复制函数的参数定义。请看示例:

def calling_trace(func):

def wrapper(a,b,c=3):

print('calling', func.__name__)

a = func(a,b,c)

print('reture value:',a)

return wrapper

@calling_trace

def test3(a,b,c=3):

print('test3 is runing...')

return a+b+c

test3(1,2,5)

test3(1,2)

装饰器返回的函数的参数定义,要与被装饰函数的参数定义保持一致!以上代码运行结果如下:

$ python3 deco.py

calling test3

test3 is runing...

reture value: 8

calling test3

test3 is runing...

reture value: 6

就算装饰参数个数不定的函数,语法上也是一样的,请看下面代码,test4函数的参数个数不定:

def calling_trace(func):

def wrapper(*args):

print('calling', func.__name__)

a = func(*args)

print('reture value:',a)

return wrapper

@calling_trace

def test4(*args):

print('test4 is runing...')

return sum(args)

test4(1,2,3,4,5,6,7,8)

test4(23,34,45,56)

*args表示一个tuple,在函数定义处出现,就是packing打包调用时的参数,在调用时出现,就是unpacking展开tuple。跟**kw(对应dict)用法一样。以上代码运行效果:

$ python3 deco.py

calling test4

test4 is runing...

reture value: 36

calling test4

test4 is runing...

reture value: 158

给带参数的函数加装饰器,还有一种更通用更常见的参数写法,这种写法在修改函数参数和调用处时,有可以反过来保持装饰器部分代码不变。示例如下:

def calling_trace(func):

def wrapper(*args, **kw):

print('calling', func.__name__)

a = func(*args, **kw)

print('reture value:',a)

return wrapper

@calling_trace

def test5(a,b,c=3):

print('test5 is runing...')

return a+b+c

test5(1,2)

test5(1,2,c=8)

装饰器中使用*args和**kw来接收和传递参数!这个地方要好好体会,这是python的一个特别精妙的地方。以上代码运行结果如下:

$ python3 deco.py

calling test5

test5 is runing...

reture value: 6

calling test5

test5 is runing...

reture value: 11

带参数的装饰器

本文以上示例,都是不带参数的装饰器,在使用@语法的时候,没有参数。而装饰器本身也可以带参数,通过在装饰器外再使用闭包,给装饰器封装其执行环境,可以使装饰器的功能更强大更灵活,也可以更好的控制函数的执行(比如在某些情况下不执行)。而带参数的装饰器,在语法上,也就跟闭包区分开来。(应该就是这个原因,闭包和装饰器在python中是分成了两个概念)

def calling_trace(run):

def deco(func):

def wrapper(*args, **kw):

print('calling', func.__name__)

if run == 1:

a = func(*args, **kw)

print('reture value:',a)

else:

print('not allow to run')

return wrapper

return deco

# test5 = calling_trace(run=1)(test5)

@calling_trace(run=1)

def test5(a,b,c=3):

print('test5 is runing...')

return a+b+c

@calling_trace(run=0)

def test6(*args):

print('test6 is runing...')

return sum(args)

test5(1,2)

test5(1,2,c=8)

test6(23,34,45,56)

先看一下这段代码的运行结果:

$ python3 deco.py

calling test5

test5 is runing...

reture value: 6

calling test5

test5 is runing...

reture value: 11

calling test6

not allow to run

达到预期,test5可以执行,而test6不允许执行。

calling_trace实际上就是一个闭包,它有一个参数,run,调用calling_trace(run=1)后,就相当于返回了一个有run这个参数的装饰器。然后再用这个装饰器去“修饰”它自己的参数func。这个效果,就如注释掉的那行代码。如果不使用@语法,把那行代码注释打开(放在test5的定义后面),运行效果一模一样!

多重装饰器

函数可以有多个装饰器!多个装饰器的效果,就相当于对函数进行了多层的封装包裹,而不同的装饰器对函数执行的功能影响,完全独立。比如有个装饰器用来控制函数是否能够被执行,另一个装饰器控制函数的所有raise出来的异常。

@a

@b

@c

def tt(): pass

# tt = a(b(c(tt)))

tt函数上面带3个装饰器,想过正如注释掉的那行代码。

我真的觉得python装饰器的设计,实在是非常精妙!

-- EOF --

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

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

相关文章

Java基础复习题--类加载顺序

在某个视频看到一个关于Java类加载顺序的面试题,记录一下: talk is sheep, show code!(请忽略语法) public class Father {private int i test();private static int j method();static {System.out.prin…

基本农田卫星地图查询_发现谷歌地图替代网站,卫星地图街景功能都能用

众所周知,由于谷歌地图(Google Maps)在国内不能访问,很多人就没有办法通过谷歌地图来获得服务。谷歌地图是目前全球最受欢迎的世界地图网站,在2005年以前,谷歌地图就收录了美国、英国、加拿大三个国家的地图…

记录 Linux crontab 的使用

记录一次简单的Linux定时任务----》每周定时备份数据库结构及数据 环境:阿里云服务器 vim 命令:输入i/a 进入输入模式,输入完成后,esc键,退出输入模式,确定无误后,输入“:wq”,保存退出 Linux 环…

python random函数_Python随机函数random使用详解

在python中用于生成随机数的模块是random,在使用前需要import, 下面看下它的用法。1、random.randomrandom.random()用于生成一个0到1的随机符点数: 0 < n < 1.0注意&#xff1a; 以下代码在Python3.5下测试通过&#xff0c; python2版本可稍加修改描述random() 方法返回…

Graphicsmagick linux 中文水印乱码-new

文章目录Graphicsmagick linux 中文水印l乱码&#xff08;中文显示成正方形&#xff09;本人在Windows上安装Graphicsmagick 并使用Graphicsmagick 添加中文水印成功&#xff0c;但是在Linux下一直乱码&#xff0c;现将解决办法分享给有需要的朋友。 1.Linux下默认安装Graphic…

python数据结构递归树_python数据结构(对称二叉树递归和迭代)

1、题目描述给定一个二叉树&#xff0c;检查它是否是镜像对称的。2、代码详解2.1 递归写法# Definition for a binary tree node.class TreeNode(object):def __init__(self, x):self.val xself.left Noneself.right Noneclass Solution(object):# 递归写法def isSymmetric(…

python跨文件复制sheet_Python办公自动化-工作表复制(可跨文件)

我们平时在处理Excel文档&#xff0c;会涉及到工作表的复制。一般我们会遇到这两种工作表复制需求&#xff1a;单个Excel文档内将工作表复制多分多个Excel文档之间&#xff0c;相互复制工作表将多Excel文档中的工作表复制到同一个Excel文档中针对与上述需求&#xff0c;我们可以…

python 神经网络原理_神经网络理论基础及Python实现

一、多层前向神经网络多层前向神经网络由三部分组成&#xff1a;输出层、隐藏层、输出层&#xff0c;每层由单元组成;输入层由训练集的实例特征向量传入&#xff0c;经过连接结点的权重传入下一层&#xff0c;前一层的输出是下一层的输入;隐藏层的个数是任意的&#xff0c;输入…

postman 使用_Postman使用方法

一 Postman背景介绍用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的&#xff0c;用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具。今天给大家介绍的这款网页调试工具不仅可以调试简单的css、html、脚本等简单的网页基…

bool python 运算_python基础知识和pycharm安装

昨天大家对我(Python)有了一定的了解&#xff0c;那么今天带大家更加系统化的认识一下我&#xff0c;已经了解我的工作方式先说一下如果让我去做一件事情得需要那些“配置”&#xff0c;其实很简单的&#xff0c;不要把我想的太复杂&#xff0c;毕竟还是个单纯的孩子。让我做事…

python send 案例_python之pexpect实现自动交互的例子

Pexpect 是 Expect 语言的一个 Python 实现&#xff0c;是一个用来启动子程序&#xff0c;并使用正则表达式对程序输出做出特定响应&#xff0c;以此实现与其自动交互的 Python 模块。 Pexpect 的使用范围很广&#xff0c;可以用来实现与 ssh、ftp 、telnet 等程序的自动交互&a…

视频显示边缘空白的真相

在多媒体开发过程中&#xff0c;难免会使用到video这一类型。但一直有部分开发者或产品人员总提出 “视频画面没有充满”其给定的窗口&#xff0c;其原因在于对视频不了解&#xff0c;想当然的去认为要“充满”。被问到此问题只能苦笑一声&#xff0c;哭笑不得。 先看下几个效果…

word公式编辑器_毕业论文里面的各种公式该如何编辑

毕业论文中很多专业都会需要书写很多公式&#xff0c;而对于对Word使用不够熟练的朋友肯定会在编辑公式上很苦恼了&#xff0c;Word自带的公式编辑器又不够方便&#xff0c;本节给大家介绍一种很方便的公式编辑方法&#xff0c;而且更改公式后公式序号会自动跟着变。安装好后打…

Gensee移动SDK之(一)结构组成

gensee 移动sdk现已更新到v3.3&#xff0c;自1.0到3.0的过度当中&#xff0c;经历了几次大的变革。每次变革都新的功能接口和结构上微妙的变化&#xff0c;但直播、点播的结构组成基本定型&#xff0c;即便是扩展也会依此延续。Sdk为了界面上的自由度&#xff0c;不提供完整的U…

python分析服务器日志_python实现web服务器日志分析脚本

python日志分析脚本用python可以实现大日志文件的分析&#xff0c;比如查到sql注入语句&#xff0c;然后看到IP&#xff0c;就可以改下脚本&#xff0c;用IP为特征取出日志&#xff0c;分析入侵过程。python比较shell脚本的优点是速度快&#xff0c;性能好&#xff0c;跑1G日志…

Gensee移动SDK之(二)协议

首先&#xff0c;对于协议而言&#xff0c;有标准的&#xff0c;也有私有的&#xff0c;就看具体使用场景的修饰与更改情况了。部分朋友在接触SDK的时候会提出此疑问&#xff0c;只能说“各怀鬼胎”。第一&#xff0c;即便我们告知我们使用的协议&#xff0c;该用sdk的时候&…

vs点击方法跳不到对于的地方_内脏脂肪怎么测?这个方法也太方便了!| EASD 2020...

我马上开始减肥还不行么&#xff1f;秋天——丰收的日子&#xff0c;看着肥美的鱼蟹&#xff0c;软糯的栗蓉&#xff0c;甜美的桂花糕&#xff0c;不认真贴秋膘都对不起这么丰盛的美食&#xff01;等等&#xff0c;别想了&#xff0c;看看肚子上层层叠起的肥肉&#xff0c;量量…

Gensee Android SDK(一)组成结构

在分支平台Android上sdk&#xff0c;基本主线不会变&#xff0c;变的只是与平台相关的部分&#xff0c;例如视频采集、音频采集、权限等。 按功能分类分为 RtSDK 重点是可以支持视频互动、发&#xff08;控制&#xff09;直播的能力。接口功能上基本上等同于PC客户端。 可以做…

python中msg是什么意思_python下载.msg文件的附件

def get_attachments(file_name, path_name):"""获取.msg文件内的附件:param file_name: .msg文件路径:param path_name: 附件存放目录:return: None"""outlook win32com.client.Dispatch("Outlook.Application").GetNamespace("…

云服务器Ubuntu系统安装apache2发生“E: Unable to locate package”

Ubuntu安装apache2发生“E: Unable to locate package”云服务器安装apache2 出错E: Unable to locate package安装apache2测试apache2安装云服务器安装apache2 出错E: Unable to locate package 最近买了个云主机&#xff0c;操作系统由centos换成Ubuntu的之后&#xff0c;先…