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语法特性,以@修饰的结构就叫做装饰器
装饰器的出现是为了更方便地进行功能拓展,但完成这样的拓展并不是非装饰器不可;
就像前边两中方式都可以实现这样的拓展,逻辑上是等价的;
只是在函数名比较长或嵌套层级比较多时,“装饰器”结构就显得比较简洁;

未完待续...

高级用法

最佳实践

标准库functools

posted on 2017-06-19 01:22  yabzhang  阅读(104)  评论(0)    收藏  举报

导航