Python的@符号 --decorator
来源:互联网 发布:员工签到软件 编辑:程序博客网 时间:2024/05/27 20:33
>>> def now():... print '2013-12-25'
假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
我们要定义一个能打印日志的decorator,可以定义如下:
def log(func): def wrapper(*args, **kw): print 'call %s():' % func.__name__ return func(*args, **kw) return wrapper
@logdef now(): print '2013-12-25'
调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:
>>> now()call now():2013-12-25
把@log放到now()函数的定义处,相当于执行了语句:now= log(now)
由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。
decorator类
class decoratorWithoutArguments(object): def __init__(self, f): """ If there are no decorator arguments, the function to be decorated is passed to the constructor. """ print "Inside __init__()" self.f = f def __call__(self, *args): """ The __call__ method is not called until the decorated function is called. """ print "Inside __call__()" self.f(*args) print "After self.f(*args)" @decoratorWithoutArgumentsdef sayHello(a1, a2, a3, a4): print 'sayHello arguments:', a1, a2, a3, a4 print "After decoration" print "Preparing to call sayHello()"sayHello("say", "hello", "argument", "list")print "After first sayHello() call"sayHello("a", "different", "set of", "arguments")print "After second sayHello() call"输出结果是:
Inside __init__()
After decoration
Preparing to call sayHello()
Inside __call__()
sayHello arguments: say hello argument list
After self.f(*args)
After first sayHello() call
Inside __call__()
sayHello arguments: a different set of arguments
After self.f(*args)
After second sayHello() call
注意,decoratorWithoutArguments的构造器(constructor)在函数的decoration处执行。由于我们可以在__init__()里面调用f(),它意味着在调用decorator前就完成了f()的创建。另外需注意,decorator构造器接收到decorated的函数对象。你将在构造器中得到函数对象,之后在__call__()方法中进行使用(当使用类时,decoration和调用是两个泾渭分明的阶段,这也是我为何说它更简单、更强大的原因)。
当decorated之后再调用sayHello(),它的行为就完全不一样了:不再用原来的代码而开始调用decoratorWithoutArguments.__call__()方法。原因是decoration过程是将decorator结果取代原先的函数--在我们的例子中,decoratorWithoutArguments对象取代了aFunction。
含有参数的decorators
class decoratorWithArguments(object): def __init__(self, arg1, arg2, arg3): """ If there are decorator arguments, the function to be decorated is not passed to the constructor! """ print "Inside __init__()" self.arg1 = arg1 self.arg2 = arg2 self.arg3 = arg3 def __call__(self, f): """ If there are decorator arguments, __call__() is only called once, as part of the decoration process! You can only give it a single argument, which is the function object. """ print "Inside __call__()" def wrapped_f(*args): print "Inside wrapped_f()" print "Decorator arguments:", self.arg1, self.arg2, self.arg3 f(*args) print "After f(*args)" return wrapped_f @decoratorWithArguments("hello", "world", 42)def sayHello(a1, a2, a3, a4): print 'sayHello arguments:', a1, a2, a3, a4 print "After decoration" print "Preparing to call sayHello()"sayHello("say", "hello", "argument", "list")print "after first sayHello() call"sayHello("a", "different", "set of", "arguments")print "after second sayHello() call"从输出结果可以看到,加入参数使程序执行发生了很大变化。
Inside __init__()
Inside __call__()
After decoration
Preparing to call sayHello()
Inside wrapped_f()
Decorator arguments: hello world 42
sayHello arguments: say hello argument list
After f(*args)
after first sayHello() call
Inside wrapped_f()
Decorator arguments: hello world 42
sayHello arguments: a different set of arguments
After f(*args)
after second sayHello() call
现在decoration方法调用构造器,然后就马上调用__call__(),后者只能包含一个参数(函数对象)且返回替代原有函数的decorated函数对象。注意当前decoration期间__call__()仅被调用一次,此后从__call__()返回的decorated函数就可以在实际调用中使用了。
虽然这种机制有一定合理性—构造器在这里可获取decorator参数,但__call__()对象不能再作为decorated函数使用了。因此你必须使用__call__()执行decoration—可能第一次遇到这种与无参情况截然不同的方式你会比较吃惊,何况还必须编写和无参decorator完成不同的代码。
含decorator参数的decorator函数
def decoratorFunctionWithArguments(arg1, arg2, arg3): def wrap(f): print "Inside wrap()" def wrapped_f(*args): print "Inside wrapped_f()" print "Decorator arguments:", arg1, arg2, arg3 f(*args) print "After f(*args)" return wrapped_f return wrap @decoratorFunctionWithArguments("hello", "world", 42)def sayHello(a1, a2, a3, a4): print 'sayHello arguments:', a1, a2, a3, a4 print "After decoration" print "Preparing to call sayHello()"sayHello("say", "hello", "argument", "list")print "after first sayHello() call"sayHello("a", "different", "set of", "arguments")print "after second sayHello() call"输出结果为:
Inside wrap()
After decoration
Preparing to call sayHello()
Inside wrapped_f()
Decorator arguments: hello world 42
sayHello arguments: say hello argument list
After f(*args)
after first sayHello() call
Inside wrapped_f()
Decorator arguments: hello world 42
sayHello arguments: a different set of arguments
After f(*args)
after second sayHello() call
参考:
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819879946007bbf6ad052463ab18034f0254bf355000
http://blog.csdn.net/beckel/article/details/3945147
- Python的@符号 --decorator
- Python:decorator的使用
- python 的decorator
- 【Python】decorator的作用
- Python的decorator使用
- python decorator的理解
- Python的装饰器(decorator)
- Python的decorator学习笔记
- Python Decorator 的来龙
- Python的装饰器decorator
- python decorator
- python decorator
- python decorator
- python decorator
- Python - Decorator
- Python decorator
- python decorator
- python decorator
- 设计模式-代理模式
- NeHe_OpenGL_第九课 3D空间中移动图像
- 将int转为string类及将string类转为int类
- MySQL报错:The MySQL server is running with the --skip-grant-tables option so it cannot execute this st
- Java多线程之CountDownLatch
- Python的@符号 --decorator
- JavaWeb文章索引
- [leetcode] Best Time to Buy and Sell Stock
- 浅析SAX,DOM,JAXP,JDOM与DOM4J之间的关系
- 12.04拷贝最好用的 linux源
- [leetcode] Best Time to Buy and Sell Stock II
- CDH功能简介
- [leetcode] Best Time to Buy and Sell Stock III
- 数据结构与程序设计第一章——编程原则