python装饰器(整理版)
Python中函数有一个装饰器的概念,今天,看核心编程中的函数一章的时候接触到了这个概念,炸一看来,讲的说明真实不好明白。于是写下本篇以示说明,提供给迷糊者。希望能对一些人起到一定的帮助
装饰器的语法以@开头,接着是装饰器要装饰的函数的申明等。
其实总体说起来,装饰器其实也就是一个函数,一个用来包装函数的函数,装饰器在函数申明完成的时候被调用,调用之后申明的函数被换成一个被装饰器装饰过后的函数。装饰器分为无参装饰和有参装饰
无参装饰很简单
定义方法如下:
比如先定义一个装饰方法:
|
1
2
3
4
5
6
|
def FirstDeco(func): print '第一个装饰器' return func@FirstDecodef test(): print 'asdf' |
申明完成之后显示(在shell里试一下就知道了)
>>>第一个装饰器
可见装饰器在函数定义完成的时候被触发
然后,咱们运行
>>>test
>>>asdf
多参装饰:
多参装饰复杂一点,多参装饰的时候,装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰
具体代码如下:
|
1
2
3
4
5
6
7
8
9
10
|
def deco(x): print '%s 开始新装饰' def newDeco(func): def test(a,b): print 'begin' returnv = func(a,b) print 'end' return returnv return test return newDeco |
这里定义了一个装饰其函数deco,里面有一个参数x,这个时候,我们没有直接使用func作为装饰函数的参数,而是只用了参数x作为参数,之后定义一个新的装饰函数,newdeco,该函数才装饰
然后定义如下:
|
1
2
3
4
5
6
|
@deco(3)def mytest(x,y): if x>y: print x else: print y |
运行之后的结果为
>>>%s 开始新装饰 >>> mytest(3,4) begin 4 end
装饰方法的产生:
Python2.2通过增加静态方法和类方法扩展了Python的对象模型。但是当时没有提供一个简化的语法去定义static/class方法,只得在定义好的方法尾部去调用staticmethod()/classmethod()方法达到目的。例如:
|
1
2
3
4
|
class C: def meth (cls): meth = classmethod(meth) # 使meth方法成为类方法 |
但是这样会造成一个问题:当一个方法比较长时,很容易忘记尾部的调用。为了简化这个操作一个新的语法被加了进来:方法装饰,以@开头后跟装饰方法 名,如@staticmethod/@classmethod,由此产生出decorator方法及decorator模式。现在我们可以这样写:
|
1
2
3
|
class C: @classmethod def meth (cls): |
可以对一个方法应用多个装饰方法:
|
1
2
3
4
5
6
7
8
|
@A@B@Cdef f (): #等价于下面的形式,Python会按照应用次序依次调用装饰方法(最近的先调用)def f():f = A(B(C(f))) |
装饰方法解析:
每个decorator只是一个方法, 可以是自定义的或者内置的(如内置的@staticmethod/@classmethod)。decorator方法把要装饰的方法作为输入参数,在函数体内可以进行任意的操作(可以想象其中蕴含的威力强大,会有很多应用场景), 只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数, 或者是一个新函数)。decorator的作用对象可以是模块级的方法或者类方法。decorator根据应用时的参数个数不同分为两类:无参数 decorator,有参数decorator。下面分别介绍。
无参数decorator:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def deco(func): """无参数调用decorator声明时必须有一个参数,这个参数将接收要装饰的方法""" print "Enter decorator" #进行额外操作 func.attr = 'decorated' #对函数进行操作,增加一个函数属性 return func #返回一个可调用对象(此例还是返回作为输入参数的方法) #返回一个新函数时,新函数可以是一个全局方法或者decorator函数的内嵌函数, #只要函数的签名和被装饰的函数相同 @decodef MyFunc(): #应用@deco修饰的方法 print "Enter MyFunc" MyFunc() #调用被装饰的函数 |
注意:当使用上述方法定义一个decorator方法时,函数体内的额外操作只在被装饰的函数首次调用时执行,如果要保证额外操作在每次调用被装饰的函数时都执行,需要换成如下的写法:
|
1
2
3
4
5
6
7
8
9
10
11
|
def deco(func): def replaceFunc(): #定义一个内嵌函数,此函数包装了被装饰的函数,并提供额外操作的代码 print "Enter decorator" #进行额外操作 return func() #产生对被装饰函数的调用 return replaceFunc #由于返回的是这个新的内嵌函数,所以确保额外操作每次调用得以运行 @decodef MyFunc(): #应用@deco修饰的方法 print "Enter MyFunc" MyFunc() #调用被装饰的函数 |
有参数decorator:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
def decoWithArgs(arg): """由于有参数的decorator函数在调用时只会使用应用时的参数而不接收被装饰的函数做为参数, 所以必须返回一个decorator函数, 由它对被装饰的函数进行封装处理""" def newDeco(func): #定义一个新的decorator函数 def replaceFunc(): #在decorator函数里面再定义一个内嵌函数,由它封装具体的操作 print "Enter decorator" #进行额外操作 return func() #对被装饰函数进行调用 return replaceFunc return newDeco #返回一个新的decorator函数 @decoWithArgs("demo")def MyFunc(): #应用@decoWithArgs修饰的方法 print "Enter MyFunc" Myfunc() #调用被装饰的函数 |
当我们对某个方法应用了装饰方法后, 其实就改变了被装饰函数名称所引用的函数代码块入口点,使其重新指向了由装饰方法所返回的函数入口点。由此我们可以用decorator改变某个原有函数的功能,添加各种操作,或者完全改变原有实现。
python装饰器(整理版)的更多相关文章
- python 装饰器 一篇就能讲清楚
装饰器一直是我们学习python难以理解并且纠结的问题,想要弄明白装饰器,必须理解一下函数式编程概念,并且对python中函数调用语法中的特性有所了解,使用装饰器非常简单,但是写装饰器却很复杂.为了讲 ...
- 转发对python装饰器的理解
[Python] 对 Python 装饰器的理解的一些心得分享出来给大家参考 原文 http://blog.csdn.net/sxw3718401/article/details/3951958 ...
- Python—装饰器详解
装饰器:(语法糖) 本质是函数,它是赋予函数新功能,但是不改变函数的源代码及调用方式 原则: 1.不能修改被装饰函数的源代码 2.不能修改被装饰函数的调用方式 3.函数的返回值也不变 这两点简而言 ...
- Python高级特性: 12步轻松搞定Python装饰器
12步轻松搞定Python装饰器 通过 Python 装饰器实现DRY(不重复代码)原则: http://python.jobbole.com/84151/ 基本上一开始很难搞定python的装 ...
- (十)Python装饰器
装饰器:本质就是函数,功能是为其他函数添加附加功能. 两个原则: 1.不修改被修饰函数的源代码 2.不修改被修饰函数的调用方式 一个栗子 def test(): res = 0 for i in ra ...
- 【低门槛 手把手】python 装饰器(Decorators)原理说明
本文目的是由浅入深地介绍python装饰器原理 装饰器(Decorators)是 Python 的一个重要部分 其功能是,在不修改原函数(类)定义代码的情况下,增加新的功能 为了理解和实现装饰器,我们 ...
- 关于python装饰器
关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...
- python装饰器通俗易懂的解释!
1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...
- Python 装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...
- python 装饰器修改调整函数参数
简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...
随机推荐
- idea中自定义设置xml的头文件的内容
因为在idea中新建的xml默认的头文件,有时候并不是我们需要的这时候可以通过自定义来解决. 如搭建hibernate的实体类的映射xml. 首先 fiel→settings出现 如下框框 在上面搜索 ...
- php集成开发环境xampp的搭建
一:运维闲谈 作为一名linux运维工程师,在确保能够有熟练的服务器的搭建和维护优化技能的前提,还需对自身解决问题方法上做出一番功夫. 如何为自己的运维工作添砖加瓦,自动化运维便变得非常重要,一方面, ...
- php 删除指定扩展名文件
<?php /** *@param $path文件夹绝对路径 $file_type待删除文件的后缀名 *return void */ function clearn_file($path, $f ...
- web worker,SSE,WebSocket,AJAX 与后端交互的方式
一 web worker web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能.您可以继续做任何愿意做的事情:点击.选取内容等等,而此时 web worker ...
- CSS选取指定位置标签first-child、last-child、nth-child
1.first-child 选择列表中的第一个标签. 2.last-child 选择列表中的最后一个标签 3.nth-child(n) 选择列表中的第n个标签 4.nth-child(2n) 选择列表 ...
- Scala构建元数据
反射方式构建元数据: 通过反射来获取RDD中的Schema信息.这种方式适合于列名(元数据)已知的情况下 步骤: 1.SparkConf配置环境 2.SparkContext初始化上下文 3.SQLC ...
- PLC状态机编程第五篇-状态机自动生成PLC程序
这篇比较简单了,我就直接上图了,不多废话. 一.选择求解器,一定要选择定步长的. 二.右击Chart状态机,出现图上菜单 三.左边红色的勾选择,选择右侧的菜单,然后点击Generate Code按钮, ...
- JS简写
本文来源于多年的 JavaScript 编码技术经验,适合所有正在使用 JavaScript 编程的开发人员阅读. 本文的目的在于帮助大家更加熟练的运用 JavaScript 语言来进行开发工作. 文 ...
- P1414 又是毕业季II (数学?
题目背景 “叮铃铃铃”,随着高考最后一科结考铃声的敲响,三年青春时光顿时凝固于此刻.毕业的欣喜怎敌那离别的不舍,憧憬着未来仍毋忘逝去的歌.1000多个日夜的欢笑和泪水,全凝聚在毕业晚会上,相信,这一定 ...
- 1082: [SCOI2005]栅栏
链接 思路 二分+搜索+剪枝. 首先二分一个答案,表示最多可以切出x块.(一个结论:切出的一定是从较小的前x块.如果一个木材可以满足很多个需要的木材,那么切出最小的,就意味着以后再选时的机会更多.) ...