下面具体看下装饰器是如何发挥作用的
首先,看装饰器函数outer,该函数接收一个参数func,其实就是接收一个方法名,outer内部又定义一个函数inner,在inner函数中执行func,同时增加了计时功能,outer的返回值为内部函数inner,其实就是一个闭包函数。
然后,再来看一下,在foo上增加@outer,那这是什么意思呢?当python解释器执行到这句话的时候,会去调用、运行outer函数,同时将被装饰的函数名作为参数传入(此时为foo),
>>> def outer(func):
... #定义一个内嵌的包装函数,给传入的函数加上计时功能的包装
... print("nowrunning")
... def inner():
print("in inner")
... start = time.clock()
... func()
... end =time.clock()
... print 'used:', end -start
... #将包装后的函数返回
... return inner
...
>>> @outer #相当于执行了foo=outer(foo)
... def foo():
... print("in foo()")
...
now running
>>>
可见在函数上添加装饰器后,第一层函数就会运行。在执行完outer函数的时候,直接把inner函数返回了,同时把它赋值给foo,此时的foo已经不是未加装饰时的foo了,而是指向了outer.inner函数地址。
接下来,在调用foo()的时候,其实调用的是outer.inner函数,那么此时就会执行计时逻辑,同时在outer.inner函数中调用执行原来的foo(),该处的foo就是通过装饰传进来的参数foo。
这样下来,就完成了对foo的装饰。实际上当python解释器执行到@outer时,就开始进行装饰了(运行装饰器函数了)。
根据原函数是否有参数和有返回值,装饰器函数略有不同。分析如下
对带有参数的函数进行装饰
如果原函数有参数,只需闭包函数和原函数持参数个数一致,并且将参数传递给原方法即可,因此闭包函数参数总是写成(*args,**kwargs)。如
import time
def outer(func):
#定义一个内嵌的包装函数,给传入的函数加上计时功能的包装
def inner(*args, **kwargs):
start = time.clock()
func(*args, **kwargs)
end = time.clock()
print('used:', end - start)
#将包装后的函数返回
return inner
@outer
def foo(*args, **kwargs):
print("in foo()")
print('%d + %d = %d ' % (args[0], args[1], args[0] +args[1]))
运行foo函数,如
>>> foo(2,3)
in foo()
2 + 3 = 5
('used:', 0.0)
>>>
可见利用python的可变参数轻松实现装饰带参数的函数。
对带有返回值的函数进行装饰
如果原foo函数有返回值。在inner函数中对foo进行了调用,如果没有用return语句,即没有进行返回,那么默认返回就是None了。
import time
def outer(func):
#定义一个内嵌的包装函数,给传入的函数加上计时功能的包装
def inner(*args, **kwargs):
'''inner decorator'''
start = time.clock()
ret = func(*args, **kwargs)
end = time.clock()
print('used:', end - start)
return ret
#将包装后的函数返回
return inner
@outer
def foo(*args, **kwargs):
'''docstring'''
print("in foo()")
return "hello"+args[0]
如果闭包函数内没有return语句,原函数将打印“hello
None”。
>>> foo("world")
in foo()
('used:', 0.0)
'hello world'
>>>
给装饰器传参
上面看到的装饰器都不能传参,如果要给装饰器传参,需要再在装饰器外部封装一层函数,然后返回这个装饰器,这样装饰器函数可以使用传入的参数了,如在outer函数外面封装一层函数,如
def wrapouter(para):
def outer(func):
#定义一个内嵌的包装函数,给传入的函数加上计时功能的包装
def inner(*args, **kwargs):
'''inner decorator'''
print("now runningfunction: "+para)
start = time.clock()
ret = func(*args,**kwargs)
end = time.clock()
print('used:', end -start)
return ret
#将包装后的函数返回
return inner
return outer
第一层函数,可以用来接收传递进来的参数;第二层函数,是接收传进来的函数对象。则装饰foo函数示例为
@wrapouter("foo") #首先执行wrapouter(‘foo’) ,再执行@outer
def foo(*args, **kwargs):
'''docstring'''
print("in foo()")
return "hello"+args[0]
运行测试
>>> foo("world")
now running function: foo
in foo()
('used:', 0.0)
'hello world'
>>>









网友评论