您的位置:首页 > 编程语言 > Python开发

python 装饰器模式 我的理解

2016-01-12 17:20 447 查看
python和javascript类似, 可以把函数当作函数的返回值, 比如

def func(f):
def subfunc():
print 'subfunc'
return subfunc
此外func的参数f也可以是一个函数,正是这样的结构让python可以实现装饰器模式

def deco(func):
    print("before myfunc() called.")
    func()
    print("  after myfunc() called.")
    return func
 
def myfunc():
    print(" myfunc() called.")
 
myfunc = deco(myfunc)
 
myfunc()
可以看到myfunc被deco包装了一下,在执行前的切面和执行后的切面都增加了一段代码,这就是装饰器的作用.

在python中还有一个语法糖的概念, 有了它装饰器模式的实现代码可以更加简洁.示意如下:

def deco(func):
    print("before myfunc() called.")
    func()
    print("after myfunc() called.")
    return func
 
@deco
def myfunc():
    print("myfunc() called.")
 
myfunc()
myfunc()

把装饰函数的名字和@符号,放到被装饰函数的上一行,python就会自动开启装饰器模式.

但是语法糖有一个问题要注意.语法糖对函数的包装只会在编译代码时进行一次.也就是说在编译的时候,python会自动执行:

myfunc = deco(myfunc)

所以如果你运行上面这段代码, 编译时会输出:

before myfunc() called.
myfunc() called.
after myfunc() called.

运行最后两个myfunc()时,又会输出:

myfunc() called.
myfunc() called.

也就是这篇文章第三步中提到的运行结果.正确的方法是定义一个函数,用这个函数作为返回值代替被装饰的函数.

def deco(func):
    def _deco():
        print("before myfunc() called.")
        func()
        print("after myfunc() called.")
    return _deco
 
@deco
def myfunc():
    print(" myfunc() called.")
    return 0
 
myfunc()
myfunc()

一个函数可以被多个装饰函数包装, 比如语法糖的顺序是

@deco_1
@deco_2
def func()
pass
那么装饰的顺序就是:

func =deco_1(deco_2(func))

此外装饰器还可以带参数, 在这种情况下装饰函数就会再多一层函数嵌套:

def deco(arg):
def _deco(func):
if arg:
def wrapper():
print("True")
rs = func()
print("after myfunc() called.")
return rs
else:
def wrapper():
print("False")
rs = func()
print("after myfunc() called.")
return rs
return wrapper
return _deco

@deco(True)
def myfunc():
print(" myfunc() called.")
return 1

aa = myfunc()
print aa
为什么呢? 因为包装过程是: 
func = deco(1)(func)
deco是一个带参数的函数, 而deco(arg)的返回值又是一个以函数为参数的"正常的"装饰函数. 而这个"正常的"装饰函数的返回值又是一个用来代替func()的已经包装好了的函数.

此外被装饰的函数也可以带参数, 装饰函数的参数还可以是一个类 等等, 我就不一一举例了,大家可以看看这几篇文章:
http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html http://www.cnblogs.com/wilber2013/p/4657155.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: