装饰器学习笔记1:函数的作用域

来源:互联网 发布:mac dosbox debug.exe 编辑:程序博客网 时间:2024/06/04 22:49

 恩,继续整理笔记,因为不熟练,感觉平时本能的不去用这个东西,汗一个先.
 发现对这里还是有时会发生混乱. 教程里各位前辈通用说法是搞懂3大前置知识后就比较容易理解了,主要是下面3个:
函数、函数作用域、闭包

 个人觉得简单的装饰器还是比较容易理解的,复杂的地方在于给装饰器加参数后,涉及嵌套层数问题,尤其层数超过3层时,逻辑很容易弄乱了,复杂程度是成倍上升,脑子不够用啊./(ㄒoㄒ)/~~
 额,从头复习一下.函数跳过
 装饰器本质还是一个函数,不过是一个复杂的嵌套函数,而且参数和返回值也可能是一个函数.这就比较难搞了点.

1. 函数作用域

def func():    age = 20
>>>print(age)NameError: name 'age' is not defined

直接报错,age是一个局部变量,只作用于函数内部,这里依据LEGB原则为L,变量搜索的优先级顺序依次是LEGB,
这里个人理解为程序已经在L级别的作用域中找到变量age,所以不会继续进行下一级的搜索.当函数执行完后,已经超出变量的作用域.这时只会在E级作用域中进行搜索,所以自然是找不到的.

L:local,局部作用域,函数中定义的变量
E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的
G:globa,全局变量,就是模块级别定义的变量
B:built-in,系统固定模块里面的变量,比如int,

def func():    class_num = 5    def inner():        age = 20    print(class_num,age)    return inner
>>>func()<ipython-input-21-826639bd4f41> in func()      3     def inner():      4         age = 20----> 5     print(class_num,age)      6     return innerNameError: name 'age' is not defined

 这里用ipython3运行,可以看到print这一句出错,按上面LEGB原则,这是因为name作用域为inner内部的L级局部作用域,print语句这里则为上一级的E级,也就是嵌套的父级函数的局部作用域,所以报错.
改造一下函数:

def func():    class_num = 5    def inner():        age = 20        print(class_num,age)    return inner
>>>a = func()>>>a()5 20

 这时可以看到正常输出了class_num和age,按照LEGB的原则,变量搜索的优先级顺序依次是LEGB,也就是先从age所在的L级作用域搜索,这时找到age,L级没有class_num,继续搜索E级作用域,成功找到class_num,则print语句正常执行 .
综合上面,
这里个人理解为可以从当前作用域层级向上级查找搜索变量,但不能向下级搜索.

name = 'lili'def func():    class_num = 5    def inner():        age = 20        print('班级:{}班 姓名:{} 年龄{}'.format(class_num,name,age))    return inner
>>>a = func()>>>a()班级:5班 姓名:lili 年龄:20

可以看到,name是更上一层的G级,即全局变量,可以在内部调用.
如果想在函数内部修改全局变量,可以用global关键字

name = 'lili'def func():    class_num = 5    def inner():        global name        age = 20        name = 'wang'        print('班级:{}班 姓名:{} 年龄{}'.format(class_num,name,age))    return inner
>>>a = func()>>>a()班级:5班 姓名:wang 年龄:20

这时就将上层的全局变量修改了,同样,如果要修改父级局部作用域的局部变量class_num,可以用另一个关键字nonlocal

name = 'lili'def func():    class_num = 5    def inner():        nonlocal class_num        age = 20        class_num = 8        print('班级:{}班 姓名:{} 年龄{}'.format(class_num,name,age))    return inner
>>>a = func()>>>a()班级:8班 姓名:lili 年龄:20

小结:
作用域共有4级,按优先级顺序依次是LEGB
L:local,局部作用域,函数中定义的变量
E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的
G:globa,全局变量,就是模块级别定义的变量
B:built-in,系统固定模块里面的变量,比如int,

可以从当前作用域层级向上级查找搜索变量,但不能向下级搜索.
调用的上级变量是不能直接进行赋值更改的,
要更改时必须用关键字 global 和 nonlocal
分别对应全局变量和父级局部作用域变量

原创粉丝点击