Python装饰器(Decorator)简介
Python有许多出色的语言特性,装饰器(Decorator)便是其中一朵奇葩。先来看看一段代码:
def deco1(f):
print 'decorate 1'
return f def deco2(f):
print 'decorate 2'
return f
@deco1
@deco2
def foo():
return 'hello'
保存并执行上面的代码,你会看到如下输出:
decorate 2
decorate 1
函数foo没有被调用,但是deco1,deco2被按照一个顺序被调用了。deco1和deco2就是装饰器。从上面的输出可以看出两点:
1 装饰器是在代码装载时被调用的
2 调用的顺是从下到上
现在来说说装配器到底做了什么。看代码:
def deco1(f):
print 'decorate 1',f
return f def deco2(f):
print 'decorate 2',f
return f @deco1
@deco2
def foo():
return 'hello'
这段代码的执行结果为:
decorate 2 <function foo at 0x00000000021F79E8>
decorate 1 <function foo at 0x00000000021F79E8>
装饰器函数的参数‘f’被打印出来,而且就是我们的函数‘foo’,可见装饰器的参数就是被装饰的函数。真的是这样吗?再来看代码:
def wraper(n,f):
def foo1():
return '%s(%s)'%(n,f())return foo1 def deco1(f):
print 'decorate 1',f
return wraper('decorate 1',f) def deco2(f):
print 'decorate 2',f
return wraper('decorate 2',f) @deco1
@deco2
def foo():
return 'hello'
这段代码的执行结果为:
decorate 2 <function foo at 0x0000000002147A58>
decorate 1 <function foo1 at 0x0000000002147AC8>
我觉得我现在可以总结一下了:
1 装饰器在代码装载时被调用;
2 调用顺序是从下到上的;
3 被装饰函数‘foo’作为参数传递给第一个装饰器‘deco2’,返回值将作为参数传递给第二个装饰器‘deco1’,然后依次向上直到最顶端的装饰器;
4 最顶端的装饰器的返回值就是被装饰以后的函数,我们暂时称之为,也就是我们将来要执行的那个‘foo’。
下面,来我们说说装饰后的函数,被调用会有什么结果,看代码:
def wraper(n,f):
def foo1():
return '%s(%s)'%(n,f())
return foo1 def deco1(f):
print 'decorate 1',f
return wraper('decorate 1',f) def deco2(f):
print 'decorate 2',f
return wraper('decorate 2',f) @deco1
@deco2
def foo():
return 'hello' print foo()
这段代码的执行结果为:
decorate 2 <function foo at 0x0000000002127A58>
decorate 1 <function foo1 at 0x0000000002127AC8>
decorate 1(decorate 2(hello))
不难看出,调用顺序与装饰顺序刚好相反,最终函数也就是最顶端的装饰器返回的函数最先被调用,然后依次调用到最初那个函数‘foo’。我在这里故意规避了一个基本的事实,就是:其实最后被调用的就是顶端装饰返回的那个函数,你必须手动在这个函数中调用前面的函数,见这里:
return '%s(%s)'%(n,f())
,才会产生调用连的效果。所以装饰器并不会帮你完成所有的事情,他给了你充分的自由。说的这里,你们要问了(如果你有足够的好奇心):‘装饰器能带参数吗’。答案是能,见下面的代码:
def wraper(n,f):
def foo1():
return '%s(%s)'%(n,f())
return foo1 def deco(n):
def deco1(f):
print n,f
return wraper(n,f)
return deco1 @deco('decorate 1')
@deco('decorate 2')
def foo():
return 'hello' print foo()
这段代码的执行结果为:
decorate 2 <function foo at 0x0000000002117AC8>
decorate 1 <function foo1 at 0x0000000002117B38>
decorate 1(decorate 2(hello))
哇,和之前的结果一模一样,代码还被简化了不少。这是怎么回事呢,我来简单解释下,函数‘deco’不是装饰器,他只是一个返回装饰器的函数,当你把它放到装饰符号‘@‘后面时,python的语法起了一个美妙的作用,他会先调用这个函数,然后用返回值值作为装饰器。
大概就是这样啦,语法大师也许会描述的更详细更专业。源码狂人还可能深入到python的C代码里寻找成因。不过,作为一个有理智的好青年我们就点到为止吧。
下次,我们再来掰扯一下,装饰器都可以变出哪些戏法吧。洗洗睡了。
Python装饰器(Decorator)简介的更多相关文章
- python 装饰器(decorator)
装饰器(decorator) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语 ...
- Python装饰器--decorator
装饰器 装饰器实质是一个函数,其作用就是在不改动其它函数代码的情况下,增加一些功能.如果我们需要打印函数调用前后日志,可以这么做 def log(func): print('%s is running ...
- Python 装饰器Decorator(一)
(一) 装饰器基础知识 什么是Python装饰器?Python里装饰器是一个可调用的对象(函数),其参数是另一个函数(被装饰的函数) 假如有一个名字为somedecorator的装饰器,target是 ...
- Python 装饰器Decorator(二)
对于上一篇“”Python闭包“”随笔中提到的make_averager()函数的如下实现,我们把历史值保存在列表里,每次计算平均值都需要重新求和,当历史值较多时,需要占用比较多的空间并且效率也不高. ...
- python 语法之 装饰器decorator
装饰器 decorator 或者称为包装器,是对函数的一种包装. 它能使函数的功能得到扩充,而同时不用修改函数本身的代码. 它能够增加函数执行前.执行后的行为,而不需对调用函数的代码做任何改变. 下面 ...
- python 装饰器学习(decorator)
最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...
- python语法32[装饰器decorator](转)
一 装饰器decorator decorator设计模式允许动态地对现有的对象或函数包装以至于修改现有的职责和行为,简单地讲用来动态地扩展现有的功能.其实也就是其他语言中的AOP的概念,将对象或函数的 ...
- python函数编程-装饰器decorator
函数是个对象,并且可以赋值给一个变量,通过变量也能调用该函数: >>> def now(): ... print('2017-12-28') ... >>> l = ...
- Python——装饰器(Decorator)
1.什么是装饰器? 装饰器放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上.和这个函数绑定在一起.在我们调用这个函数的时候,第一件事并不是执行这个函数,而是将这个函数做为参数传入它头顶 ...
随机推荐
- ADC for programmable logic uses one capacitor
Many electronic devices require user input for setting the application properties. Typical input dev ...
- busdog is a filter driver for MS Windows (XP and above) to sniff USB traffic.
https://code.google.com/p/busdog/ busdog is a filter driver for MS Windows (XP and above) to sniff U ...
- Delphi DLL制作和加载 Static, Dynamic, Delayed 以及 Shared-Memory Manager
一 Dll的制作一般分为以下几步:1 在一个DLL工程里写一个过程或函数2 写一个Exports关键字,在其下写过程的名称.不用写参数和调用后缀.二 参数传递1 参数类型最好与window C++的参 ...
- NativeXml: A native Delphi XML parser and writer
http://www.simdesign.nl/xml.html This software component contains a small-footprint Object Pascal (D ...
- U3D内存优化
原创文章如需转载请注明:转载自风宇冲Unity3D教程学院 U3D内存优化 读了Hog关于内存管理文章 ...
- Nginx集群
转自:http://hi.baidu.com/xingyuanju/blog/item/779a2a23b7ebb749935807f1.html http://hi.baidu.com/dianhu ...
- 【GISER && Painter】Chapter00:OpenGL原理学习笔记
说明:简单了解一下OpenGL的工作原理,初步认识计算机对于图形渲染的底层设计与实现,第一次接触,也没学过C艹,欢迎各位批评指正. 一 什么是OpenGL? OpenGL是一个开放标准(specif ...
- 把Java数组转换为List时的注意事项
本文由 ImportNew - 飘扬叶 翻译自 mlangc.欢迎加入翻译小组.转载请见文末要求. 不幸的是并不是每件事都尽如人意.举个例子,现在将一个Java数组转换为List.当然,我们可以使用A ...
- getaddrinfo详解
#include <sys/socket.h> #include <netdb.h> int getaddrinfo(const char *restrict nodename ...
- (队列的应用5.3.1)ZOJ 3210 A Stack or A Queue?根据进入结构的序列和离开结构的序列确定是stack还是queue)
/* * ZOJ_3210.cpp * * Created on: 2013年10月30日 * Author: Administrator */ #include <iostream> # ...