Python作用域
最近在解Leetcode题的时候,感觉自己对于Python的作用域很模糊,什么时候加self,什么时候用global nonlocal关键字,完全在摸黑探索,故准备对此进行总结。
LEGB
提到Python作用域,最重要的就是LEGB原则。
- L:local,局部作用域,即函数中定义的变量;
- E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
- G:globa,全局变量,就是模块级别定义的变量;
- B:built-in,系统固定模块里面的变量,比如int, bytearray等。
搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
通过一个例子弄明白4个作用域:
x = int(3.9) #int built-in ,系统固定模块里面的变量;
g_count = 10 #globa,全局变量;
def outer():
e_count = 1 #enclosing,包含此函数的上级函数的局部作用域,但不是全局;
def inner():
l_count = 2 #local,局部作用域,函数中定义的变量;
print(o_count)
inner()
outer()
local和enclosing是相对的,enclosing变量相对上层来说也是local。
因此,若是内部作用域想修改外部作用域的变量,就需要用到global nonlocal关键字。
修改全局作用域的变量
在子函数中global声明想要修改的变量:
count = 20
def outer():
global count
print(count)
count = 200
print(count)
outer()
修改外部嵌套函数作用域的变量
global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,若是想要修改嵌套作用域(enclosing)的变量则使用nonlocal声明。
def outer():
num = 20
def inner():
nonlocal num
num = 100
print(num)
inner()
print(num)
outer()
作用域的产生
在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域。
像if try for这些代码块是不会引入新的作用域的。
牢记LEGB原则
self指的是类的实例,所以self.xx是这一实例的属性,类内部都可以访问。
值得一提的是,这一原则似乎仅针对于int string等变量,当我在enclosing作用域声明对象、数组时,在子函数中未使用nonlocal函数依旧可以访问到。
以上,我们明确了Python的作用域概念,在将来的Leetcode解题过程中想必不会再出现访问不到变量的尴尬情况了。