3.装饰器
引言
本文是系列的第三篇,主要讲述Python中装饰器的原理和实际使用。
装饰器的使用会降低函数的效率和增加调试难度,但是却可以给代码带来更多的灵活性;所以相对于这点小问题,我们更看重“装饰器”给开发效率带来的增幅,而且装饰器的代码会更加的优雅和简洁;
装饰器
装饰器的名字源于设计模式中的“装饰器模式”,主要用于拓展新的功能;
Python的装饰器也是用于提供额外的拓展功能,而不用对函数或者类声明进行修改;
Python中装饰器和函数有着紧密关系。要讲清楚装饰器,首先需要明确在Python中,函数作为"第一类对象"首先是个对象,并且函数对象是可以被赋值给变量的,也可以作为函数的参数和返回结果。
函数是个对象,直接上代码:
def func_sample():
pass
print func_sample
<function func_sample at 0x7f75c74e8a28>
import types
isinstance(func_sample, types.FunctionType)
True
从上面的代码可以说明,函数是一个类型为FunctionType的对象;
函数对象可以被赋值给变量:
def say_hello():
print "Hello, world"
say_hello()
Hello, world
new_name = say_hello
new_name()
Hello, world
函数可以被赋值给另外的变量,并且依然可以被调用;
那么同理,函数可以作为函数的参数和返回结果也就很容易理解了:
def say_hello():
print "Hello, world"
def exe_some_func(func):
func()
return
exe_some_func(say_hello)
Hello, world
def dispatch_func():
return say_hello
f = dispatch_func()
f()
Hello, world
在上述的代码中,函数不论是作为函数的参数还是返回结果,都可以正常执行;Python的函数相当灵活的;
那么什么是装饰器呢?
其实在上述的示例代码中,已经基本有了装饰器的雏形;下面稍微做点修改:
import time
def benchmarks_func_exe(func):
def wrapped()
t0 = time.time()
result = func()
print func.__name__, time.time() - t0
return result
return wrapped
def say_hello():
print "Hello, world"
say_hello = benckmarks_func_exe(say_hello)
say_hello()
Hello, world
say_hello, 0.00004196
在上面的代码中,先约定我们要执行的目标函数是say_hello,相对于直接对目标函数进行调用,我们把say_hello作为变量传到另外一个函数中来执行;在benchmarks_func_exe中增加统计函数执行时间的逻辑,而且这个逻辑是与我们的目标函数独立的。我们可以传递任何函数对象到这个函数中,且与计时的逻辑互不影响;事实上,我们实现了对say_hello实现了功能拓展,但并没有对函数本身进行改动;
而且,由于Python的语法特性,我们可以用更加简洁的方式实现上述的功能:
import time
def benchmarks_func_exe(func):
def wrapped()
t0 = time.time()
result = func()
print func.__name__, time.time() - t0
return result
return wrapped
def say_hello():
print "Hello, world"
@benchmarks_func_exe
def say_hello():
print "Hello, world"
say_hello()
Hello, world
say_hello 0.000550985336304
这种利用Python语法特性,以@修饰的结构就叫做装饰器;
装饰器的出现是为了更方便地进行功能拓展,但完成这样的拓展并不是非装饰器不可;
就像前边两中方式都可以实现这样的拓展,逻辑上是等价的;
只是在函数名比较长或嵌套层级比较多时,“装饰器”结构就显得比较简洁;
未完待续...
浙公网安备 33010602011771号