Python - decorator
来源:互联网 发布:java 读取pdf文件 编辑:程序博客网 时间:2024/05/22 13:42
Decorators
“装饰器是一种对函数或者类指定代码管理的一种方式”...“装饰器本身是可调用的函数,并且返回一个可调用的函数” - Mark Lutz
一个函数对象是可调用的。所以,上面那句表达可以翻译为:一个装饰器是一个函数,它的参数为一个函数对象,返回值也为一个函数对象,在这个过程,可以对输入函数做必要的修改,从而增强它的功能。
“实际上,你可以使用Python的装饰器来实现装饰器模式,但是那是一个极端限制它使用的一个例子。我认为,Python的装饰器很像宏...我认为说在一门语言中宏的作用是提供了一种方法去修改语言的成分,这应该是比较恰当的。那就是装饰器在Python所做的--它修改函数,类的装饰器则修改整个类。这就是为什么他们经常提供一个简单的可选方法到元类上。” - Brue Eckel在Decorators I: Introduction to Python Decorators这样阐述到。
装饰器以不修改函数本身的前提下包装了一个函数。包装的结果为?
- 增加函数的功能。
- 修改函数的行为。
Function Decorators
让我们以Python的一个函数开始。为了理解装饰器,我们需要知道Python函数的能力范围。在Python中所有东西都是一个对象。函数也不例外。
>>> a=10>>> def f():... pass...>>> class MyClass():... pass...>>> print dir()['MyClass', '__builtins__', '__doc__', '__name__', '__package__', 'a', 'f']正如我们看到的,f()是一个对象,和类(MyClass)还有变量(a)没有什么不同。
我们可以将一个函数赋值给一个变量,所以下面几行代码是完全正确的。
def func(): print "func()"funcObj = funcfuncObj()函数可以以任何其它对象类型,比如字符串,整数,列表等传入。Python中的函数的另一方面为它可以接收一个函数作为参数并且返回一个新的函数对象。如下所示。
def myFunction(in_function): def out_function(): pass return out_function在这里myFunction实际上就是一个装饰器,因为根据定义:一个装饰器是一个函数,它可以将一个函数对象作为它的参数,并且返回一个函数对象。
如果我们精心修改一下我们刚刚定义的函数:
def myFunction(in_function): def out_function(): print "Entry: ", in_function.__name__ in_function() print "Exit: ", in_function.__name__ return out_function然后,我们该怎么调用我们的装饰器呢?
让我们看下面的例子。我们放了一个simple_function到装饰器(myFunction)中,作为它的一个参数,得到了一个enhanced_function作为装饰器的返回值。
def simple_function(): passenhanced_function = myFunction(simple_function)在许多情况下,我们将返回的函数对象取与输入函数相同的名字。所以,尤其地,代码应该看起来如下:
def simple_function(): passsimple_function = myFunction(simple_function)如果我们应用装饰器语法到上面的代码中:
@myFunctiondef simple_function(): pass注意:第一行的@myFunction不是一个装饰器,而是一个装饰器行或者是一个注释行。@标志装饰器的应用。装饰器是一个函数它接受另一个函数作为参数,并且返回一个新的函数。在我们的case中,就是myFunction。
当我们的编译器解析上面的代码时,simple_function()被编译并且它的返回函数对象传给myFunction,做了一些事情并产生一个像函数的对象并将原来的simple_function()替换掉。
同样,注意这一行:
simple_function = myFunction(simple_function)装饰器(myFunction)重新绑定装饰器的结果到函数名。所以,当后面simple_function被调用,它实际上调用的是装饰器返回的对象。
当我们定义了一个静态方法时,我们见识了重新绑定(rebinding):
>>> class A:... def s(x):... print(x)... s = staticmethod(s)... >>> A.s(10)10使用装饰器来表达同样的意思则看起来是:
>>> class A:... @staticmethod... def s(x):... print(x)... >>> A.s(10)10另外一个例子:假设我们有两个函数,它们的定义如下:
>>> def wrapper(f):... return f... >>> def foo():... pass...
然后,wrapper可以用来重新绑定foo()函数像下面这样:
>>> foo = wrapper(foo)所以,它是一个装饰器:
>>> @wrapper... def foo():... pass用一个装饰器定义如下:
def decorator(f): #process function return f它自动地匹配到:
@decoratordef f(arg): return arg*argf(123) # output 15129与下面的形式有相同的效果:
def f(arg): print arg*argf=decorator(f)装饰器是一个可调用对象并且返回一个可调用对象,该对象有与f有相同数量的参数。
所以,装饰匹配如下行:
f(123)到
decorator(f)(123)上面两个函数产生相同的结果。
例子1 - 增加$符号到price()函数的返回值
如我们想要一个函数增加一个前缀,装饰器可以帮助我们:
def dollar(fn): def new(*args): return '$' + str(fn(*args)) return new@dollardef price(amount, tax_rates): return amount + amount*tax_rateprint price(100,0.1)输出为:
$110
dollar装饰器函数取price()函数,经过修改内部工作,从原先的price()返回一个增强的输出。注意:装饰器使得我们可以在不对price()函数做任何修改的前提下实现这个功能。
所以,装饰器像一个wrapper,在目标函数执行的前后修改代码的行为,而且不需要更改函数本身,并增强了原来函数的功能。
我们也可以有一个英镑的功能:
def pound(fn): def new(*args): return (u"\u00A3").encode('utf-8') + str(fn(*args)) return '$' + str(fn(*args)) return new@pounddef price(amount, tax_rate): return amount + amount*tax_rateprint price(100, 0.2)
输出结果为:
£110
def count(f): def inner(*args, **kargs): inner.counter += 1 return f(*args, **kargs) inner.counter = 0 return inner@countdef my_fnc(): passif __name__ == '__main__': my_fnc() my_fnc() my_fnc() print 'my_fnc.counter=', my_fnc.counter
输出为:
my_fnc.counter= 3
import timedef timer(f): def inner(*args, **kargs): t = time.time() ret = f(*args, **kargs) print 'timer = %s' %(time.time()-t) return ret return inner@timerdef my_func(): passif __name__ == '__main__': my_func()Output:
timer = 5.96046447754e-06例子4 - 装饰器链
def bold(f): def wrapped(): return '<b>' + f() + '</b>' return wrappeddef italic(f): def wrapped(): return '<i>' + f() + '</i>' return wrapped@bold@italicdef hello(): return 'hello'print hello()输出:
<b><i>hello</i></b>
本文翻译自Python - decorator
0 0
- 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
- Eclipse连接SQL Server 2008
- linux maven的配置小结
- yii控制器传值到layout方法
- 用户级线程
- 如何使用GIST+LIBLINEAR分类器提取CIFAR-10 dataset数据集中图像特征,并用测试数据进行实验
- Python - decorator
- Android 项目利用 Android Studio 和 Gradle 打包多版本APK
- JAVA建造者模式
- ImageView的setScaleType
- 二叉树的基本操作
- hdu 2602 Bone Collector
- jQuery取得select选中的值
- dubbo调用未知的名称或服务
- 深入浅出MyBatis-Sqlsession