笔记-python-装饰器
笔记-python-装饰器
1. 装饰器
装饰器的实质是返回的函数对象的函数,其次返回的函数对象是可以调用的,搞清楚这两点后,装饰器是很容易理解的。
1.1. 相关概念理解
首先,要理解在Python中,函数也是一种对象
def foo(x):
print(x)
print(type(foo))
>>><class 'function'>
查看函数拥有的方法:
dir(foo)
>>>
['__call__',
'__class__',
'__closure__',
'__code__',
'__defaults__',
'__delattr__',
……]
因为函数是对象,所以函数可以作为参数传入另一个函数:
def bar(f, x):
x += 1
f(x)
bar(foo, 4) 5
1.2. 返回函数的函数
修饰函数是这样的一种函数,它接受一个函数作为输入,通常输出也是一个函数:
示例:
def loud(f):
def new_func(*args, **kw):
print('calling with', args, kw)
rtn = f(*args, **kw)
print('return value is', rtn)
return rtn
return new_func
loudlen = loud(len)
lisa = [10,20,30]
loudlen(lisa)
>>> loudlen
<function loud.<locals>.new_func at 0x000000894F4A2E18>
>>> len
<built-in function len>
解释:
在python中变量其实都是指针,对象、包括函数也是,可以相互赋值,下面也是合法的语句,在这个基础上理解容易得多;
loudlen1 = loudlen
loudlen1([10,20,30])
1.3. 使用 @
@是一个语法糖,与其说是修饰函数倒不如说是引用、调用它修饰的函数。
下面的一段代码,里面两个函数,没有被调用,也会有输出结果:
# 原理
def test(f):
print("before ...")
f()
print("after ...")
@test
def func():
print("func was called" )
直接运行,输出结果:
before ...
func was called
after ...
上面代码只定义了两个函数: test和func。没有地方调用它们。如果没有“@test”,运行应该是没有任何输出的。
但是,Python解释器读到函数修饰符“@”的时候,后面步骤会是这样了:
1. 去调用 test函数,test函数的入口参数就是那个叫“func”的函数;
2. test函数被执行,入口参数的(也就是func函数)会被调用(执行);
换言之,修饰符带的那个函数的入口参数,就是下面的那个整个的函数。
再来看一个例子:
def test(func):
func()
print("call test")
def test1(f):
f()
print( "call test1")
def main():
@test
def fun():
print("call fun")
@test1
def fun1():
print( "call fun1")
main()
输出结果:
call fun
call fun1
call test1
call test
仔细体会调用顺序。
需要注意的:
1. 函数先定义,再修饰它;反之会编译器不认识;
2. 修饰符“@”后面必须是之前定义的某一个函数;
1.4. 多重装饰
def first(func):
print('%s() was post to first()'%func.__name__)
def _first(*args,**kwargs):
print('call the function %s() in _first().'%func.__name__)
return func(*args, **kwargs)
return _first
def second(func):
print('%s() was post second()'%func.__name__)
def _second(*args, **kwargs):
print('call the function %s() in _second.'%func.__name__)
return func(*args, **kwargs)
return _second
@first
@second
def test():
return 'hello'
输出:
test() was post second()
_second() was post to first()
>>> test()
call the function _second() in _first().
call the function test() in _second.
'hello'
>>> test
<function first.<locals>._first at 0x000000A71BCBE488>
有意思的是在视觉效果上装饰器解释时是由内向外的,而执行时是由外至内的。
上面的代码实质上相当于下面的代码:
>>> def test():
return 'hello world'
>>> test=second(test)
test() was post to second()
>>> test
<function _second at 0x000000000316D3C8>
>>> test=first(test)
_second() was post to first()
>>> test
<function _first at 0x000000000316D358>
>>> test()
Call the function _second() in _first().
Call the function test() in _second().
'hello world'
1.5. 带参数的装饰器
上面都是无参数装饰,下面是一个有参数装饰的例子:
# 装饰器带参数
def log(text):
def decorator(func):
def wrapper(*args,**kw):
print("%s %s():" %(text, func.__name__))
print(args,kw)
return func(*args, **kw)
return wrapper
return decorator
@log("execute")
def now(*args,**kwargs):
print("time.ctime()")
now(1,2,3)
输出:
execute now():
(1, 2, 3) {}
time.ctime()
上面的@log(“execute“)等价于
now = log(“execute”)(now)
>>> now
<function log.<locals>.decorator.<locals>.wrapper at 0x000000B1AA97E400>
2. 附录:
面向切面编程AOP (Aspect Oriented Programming):
AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

浙公网安备 33010602011771号