1. python中函数的特性
python中,一切皆对象,函数也不例外,故python中函数的以下4个核心特性也就不难理解了:
函数可作为变量进行传递
函数可作为入参进行传递
函数可作为返回值进行传递
嵌套函数可以跨域访问(闭包)
def func():
return '函数func'
def outer(x): # 函数作为入参进行传递
def inner():
return '戴了inner帽子的' + x() # 嵌套函数inner跨域访问x
return inner # 函数作为返回值进行传递
closure = outer(func) # 函数作为变量进行传递
print(func())
print(closure())
2. python装饰器
第一部分的实例,即是装饰器的雏形了。
装饰器主要用于将 待装饰对象
进行一次外部封装,可以理解为在调用待装饰对象前后各安置一个钩子,在不改变 待装饰对象及其调用方式的前提下 进行封装。
2.1 装饰器必须要遵守的两原则
由以上描述,可以看出,装饰器必须要满足以下两个原则才能够满足需求:
不修改被装饰函数的源码;
不修改被装饰函数的调用方式。
以上两点并不难理解,在既有庞大代码中,如果无法满足上述两点中的任何一点,在使用时都将需要对现有代码做较大调整,这无疑是失败的设计。
2.2 函数装饰器实现
将以上例子进行稍微改造,即可满足装饰器遵守原则:
def func():
return '原型函数func,装饰器不应该影响我'
def outer(x):
def inner():
print("我是装饰函数前置钩子")
return x() # 满足原则1
return inner
In [3]: repr(func)
Out[3]: '<function func at 0x6fffd3ef268>'
func = outer(func) # 满足原则2
print(func())
输出:
我是装饰函数前置钩子
原型函数func,装饰器不应该影响我
In [5]: repr(func)
Out[5]: '<function outer.<locals>.inner at 0x6fffd50cea0>'
将原型func以入参形式传入outer;
outer内部的嵌套函数inner首先调用前置钩子(此处以简单的print代替),再调用原型函数func,并将其返回值传出,但此时并没有真正执行函数,因为 return x()
实际是定义在嵌套函数中,并未真正执行;
outer将嵌套函数inner作为函数对象传出,待真正调用时执行;
为了满足装饰器原则2,需要将outer返回的函数对象(inner)重命名为func,以便在现有源代码不变的前提下,将调用装饰函数inner修改为调用原函数func,但此时的func,已经非原型函数func了,可以从前后两次的 repr(func)
看出,对象已经发生改变。
经过以上实例,已经可以看到装饰器实现的原型及基本原理了。
2.3 装饰器的执行时机
当模块被load时,被装饰的函数即会执行装饰函数,成为 import time
@outer
def func()
实际上等价于 outer = outer(func)