恩,继续整理笔记,因为不熟练,感觉平时本能的不去用这个东西,汗一个先.
发现对这里还是有时会发生混乱. 教程里各位前辈通用说法是搞懂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 inner
NameError: 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
分别对应全局变量和父级局部作用域变量