Python中函数有一个装饰器的概念,今天,看核心编程中的函数一章的时候接触到了这个概念,炸一看来,讲的说明真实不好明白。于是写下本篇以示说明,提供给迷糊者。希望能对一些人起到一定的帮助
装饰器的语法以@开头,接着是装饰器要装饰的函数的申明等。
其实总体说起来,装饰器其实也就是一个函数,一个用来包装函数的函数,装饰器在函数申明完成的时候被调用,调用之后申明的函数被换成一个被装饰器装饰过后的函数。
装饰器分为无参装饰和有参装饰
无参装饰很简单
定义方法如下:
比如先定义一个装饰方法:
def FirstDeco(func):
print '第一个装饰器'
return func
@FirstDeco
def test():
print 'asdf'
....
申明完成之后显示
...
第一个装饰器
可见装饰器在函数定义完成的时候被触发
然后,咱们运行test
获得asdf
多参装饰:
多参装饰复杂一点,多参装饰的时候,装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰
具体代码如下:
>>> 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,该函数才装饰
然后定义如下:
>>> @deco(3)
... def mytest(x,y):
... if x>y:
... print x
... else:
... print y
...
%s 开始新装饰
运行之后的结果为
%s 开始新装饰
>>> mytest(3,4)
begin
4
end
参考资料:
装饰方法的产生:Python2.2通过增加静态方法和类方法扩展了Python的对象模型。但是当时没有提供一个简化的语法去定义static/class方法,只得在定义好的方法尾部去调用staticmethod()/classmethod()方法达到目的。例如:
![](https://i-blog.csdnimg.cn/blog_migrate/7d388d3aa6d3ef420a56b5c968be460b.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/cab499a6f26bdd434ece793b94b9daab.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/666cd31b35b736c18ddfe60284ad3374.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/991dddb7c3aa60eb65dd50d113a6c7fb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/5f682139d7223d27d349567d67a43808.gif)
但是这样会造成一个问题:当一个方法比较长时,很容易忘记尾部的调用。为了简化这个操作一个新的语法被加了进来:方法装饰,以@开头后跟装饰方法 名,如@staticmethod/@classmethod,由此产生出decorator方法及decorator模式。现在我们可以这样写:
![](https://i-blog.csdnimg.cn/blog_migrate/620afb5139c4039485fcc9f9c1fd63b6.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/24f83d38817f3a1958a2dee5bdb00f38.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3396c8eafac3ccc84cb4c35496d46e94.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3ea2d58c5b71a2f2005824f15eeb50df.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6b44601c525b4ef0bb30d2e37445df6d.gif)
可以对一个方法应用多个装饰方法:
![](https://i-blog.csdnimg.cn/blog_migrate/2835a87e2a834fb3f642e29cec06b162.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/096085f8eeb717bd56a63fa0714665cb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f750f8e50ec1f93a46225d766158a3a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0a620ad2f7ccad0b4289c4aaece846d7.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/903e3dc190291faf5a12214686495a08.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f5b1e9a54b694ec7a706dd38a53a7c43.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/c8739041a3606360f50d214f0a227dad.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b6481286ac2e306182c03cd166081076.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b872c0e27ba5f953b71a375adab15ed3.gif)
每个decorator只是一个方法, 可以是自定义的或者内置的(如内置的@staticmethod/@classmethod)。decorator方法把要装饰的方法作为输入参数,在函数体内可以进行任意的操作(可以想象其中蕴含的威力强大,会有很多应用场景), 只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数, 或者是一个新函数)。decorator的作用对象可以是模块级的方法或者类方法。decorator根据应用时的参数个数不同分为两类:无参数 decorator,有参数decorator。下面分别介绍。
无参数decorator:
![](https://i-blog.csdnimg.cn/blog_migrate/da269fb4da41a762867d9461bcdcb9ee.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/897b3c88a623e29457e80aa04eac69ef.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9ac79ec7fb467ce48179906d67251130.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/be1f3782b4170daf058159db8361cdfc.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1a6b157287492f311039ca2b43fc1cc2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d4bb0b76be961168517922ac97b34c60.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd68838d41b05f69a481cc0a8ca54de.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/949538a512615d8f01806edeba94d506.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9feabb24091ae035a56932ac211cb15c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/784435430386207a817755ac9363620e.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/360320f8b06cc923c8a4a349b9585938.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/64bfbd388a1e3221219cbafb929089c1.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a0dd94c73f212cefac3a8dfb716bf3de.gif)
注意:当使用上述方法定义一个decorator方法时,函数体内的额外操作只在被装饰的函数首次调用时执行,如果要保证额外操作在每次调用被装饰的函数时都执行,需要换成如下的写法:
![](https://i-blog.csdnimg.cn/blog_migrate/ad074e51e445277d6ca0e8921fb7f679.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/05b6d0f434d550efc32a847859909ccf.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/73a8e854d342154dd8aca4bf68180e74.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/fa02de43c9492f01b3198ab293009297.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/264cefddb10a5465a907aa4a9f418f97.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7e76b4983b8a5b12e889f48c5783d832.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/5f49e0836e83b22824e77289f07dd87c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7927346343e587100a3c3a45b1d4962d.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/2ace895aeafbc9651a621fb0af47bac9.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b3af1e6c119b644687e0ae4b4a644567.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/31a74fba30cef92caee83301836be11c.gif)
有参数decorator:
![](https://i-blog.csdnimg.cn/blog_migrate/2f954b1a62d618776ec648239c014aa2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/74d168be0fdd2abb44fb11b32cf199e2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a6ce1c8e1ee4c22f20086fb7c9b2c821.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/364bb490c7faddfe879f564ba01d8c0f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1cee18771fe9e8c11d57e5509cc93bb4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/66aa7c44d92d04c12a239ee74966ce5a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/de3d5c6102b2dccff93a0d6546df5688.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eb23dafc9fbfa2b2c8c3dd4a01bf1760.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/2966f6120c9a3870aea60924158da13c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6ed3a914fed88184edc5ae4b6429b163.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d4f81f3eb08e5d578a2b2317dc5b2ec1.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/5b240868674a253f806545ebf6bc1f32.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/844facaccad67bf08e1abf9449e315c7.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f63f582cd262220b29a0f99cbba2d65f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/cf45c38db249da26a6b95b5e73089c54.gif)
当我们对某个方法应用了装饰方法后, 其实就改变了被装饰函数名称所引用的函数代码块入口点,使其重新指向了由装饰方法所返回的函数入口点。由此我们可以用decorator改变某个原有函数的功能,添加各种操作,或者完全改变原有实现。