第六课.Python函数(三)

函数的嵌套与闭包

函数的嵌套是指在函数内再定义一个函数,举个例子:

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__里面,这就是闭包,闭包指的是:内部函数可以使用外部函数的变量

LEGB访问中的E

现在可以补充E空间了,E就是指闭包对象,只有出现嵌套函数情况才有E空间,访问会从内层函数的locals()开始,到外部函数的locals()即闭包Enclose空间,再到globals(),最后搜索到builtins;
当然,Enclose空间并不完全指外层函数的locals(),准确来说,是外层函数与内层函数相交的那部分对象才是Enclose空间

python装饰器

在前面嵌套函数的基础上,看懂装饰器就会变得很容易,在开始之前,先想想为什么会需要装饰器?
出现它的目的,主要是用于为不同的函数增加相同的功能,减少代码重复,假设有以下函数:

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()

结果如下:
fig2
可以看出,装饰器让函数新增功能的定义和调用更加简洁,在为函数增加功能的同时,不改变函数的调用,使代码易于维护

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值