函数的嵌套是指在函数内再定义一个函数,举个例子:
def outter(): name='jack'#被下层函数使用 age=20#被下层函数使用 address='YN'#被下层函数做返回值 height='178'#没有被下层函数使用 def inner(): new_name=name[0:3] new_age=age+1 inner_l=locals() inner_g=globals() return address,inner_l#address使用outter的 return inner#返回不是值对象,是函数对象注意到外层函数返回的是内层函数对象,如果我调用: inner=outter() 结果为:
<function __main__.outter.<locals>.inner()>可以看出inner是outter的locals()空间下的函数对象,再回顾以前说过,函数名返回的只是函数本身,如果要彻底调用inner,需要写inner(),即outter()();注意一下:outter()只是inner本身 观察内层函数inner,里面有一句:inner_l=locals(),然后这个inner_l在内层函数结尾时被return了,这说明我们只要调用了inner将可以查看到内层函数的locals()命名空间,所以调用inner()看一下:也就是调用outter()()
('YN', {'address': 'YN', 'age': 20, 'name': 'jack', 'new_age': 21, 'new_name': 'jac'})元组里第一个’YN‘应该是address,第二个字典就是inner的locals()空间,发现没有外部函数的height(注意内部函数没有用到height),而其他在外部函数中用到的对象都出现在了inner的空间里,这就是闭包; 可以dir()查看一下内层函数对象包含的对象:
inner=outter() dir(inner)发现有一个对象叫inner.__closure__,我们查看这个对象的内容有:
(<cell at 0x7f271534c828: str object at 0x7f27152d86c0>, <cell at 0x7f271534ca38: int object at 0xa6a000>, <cell at 0x7f271534c7f8: str object at 0x7f27152d8688>)可见,__closure__中保存了inner需要用到的外部变量str:name,int:age,str:address,而height没有用到,所以不在__closure__里面,这就是闭包,闭包指的是:内部函数可以使用外部函数的变量
现在可以补充E空间了,E就是指闭包对象,只有出现嵌套函数情况才有E空间,访问会从内层函数的locals()开始,到外部函数的locals()即闭包Enclose空间,再到globals(),最后搜索到builtins; 当然,Enclose空间并不完全指外层函数的locals(),准确来说,是外层函数与内层函数相交的那部分对象才是Enclose空间
在前面嵌套函数的基础上,看懂装饰器就会变得很容易,在开始之前,先想想为什么会需要装饰器? 出现它的目的,主要是用于为不同的函数增加相同的功能,减少代码重复,假设有以下函数:
def func1(): print("1") def func2(): print("2") def func3(): print("3")现在要给它们加上同样的功能,我在刚接触python时,会选择无脑地为每个函数重复写上同样的功能:
def func1(): print("1") print("add func") def func2(): print("2") print("add func") def func3(): print("3") print("add func")在发现函数也可以作为参数后,我想到了一个方法,看似简单了一点(注意这不是嵌套函数,因为我没有在函数内定义函数):
def add_func(func): print("add func") return func #调用:参数更换函数名即可,如func1,func2,func3都行 add_func(func1)() """ 输出 add func 1 """但是总感觉不够美观,于是开始使用装饰器,首先装饰器函数的定义需要遵循格式,它是使用嵌套函数定义的:
def outter(func): print("可以在这里执行增添功能") def inner(): print("也可以在这里执行增添功能") #执行被装饰的函数 func() return None return inner#外层函数必须返回内层函数对象 #注意装饰器的使用格式 @outter def myfunc(): print("这里执行被装饰的函数") #调用:直接写函数名 myfunc()结果如下: 可以看出,装饰器让函数新增功能的定义和调用更加简洁,在为函数增加功能的同时,不改变函数的调用,使代码易于维护