作用域简介

在一个程序或函数中使用变量名时,Python创建、改变和查找变量名都是在所谓的命名空间(变量名存在的地方)中进行的。Python中的变量名在第一次赋值时才能存在,并且必须经过赋值后才能使用
因此,在代码中给一个变量赋值的地方决定了这个变量将存在于哪个命名空间,也就是它的可见范围。

变量的作用域指的是变量起作用的范围。Python 中变量的作用域有4种,即局部作用域(L),嵌套作用域(E),全局作用域(G),内置作用域(B)。

python 局部变量释放 python中局部变量的作用域_嵌套

局部作用域

局部作用域(函数)中定义的变量称为局部变量,其作用域为从定义变量处开始到函数结束。

def myfunc(a):
    print(a)
    b=3
    print(b)
myfunc(2)
2
3
print(a) 
NameError: name 'a' is not defined
print(b)
NameError: name 'b' is not defined

嵌套作用域

每次调用嵌套函数中的外函数时都会创建一个嵌套作用域。

def outer():
    m=5
    def inner():
        print(m)
    inner()
outer()
5
print(m) 
NameError: name 'm' is not defined

全局作用域

每次运行模块(py文件)时都会创建一个全局作用域,如下所示变量g为全局变量。

g=18
def f():
	pass

内置作用域

每次启动python解释器都会自动加载内置模块,从而创建一个内置作用域。
内置作用域是通过一个名为builtins的标准库模块来实现,但是必须要导入之后才能使用。

import builtins
print(dir(builtins))
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError',...

LEGB

作用域访问变量时,会按照LEGB的顺序依次搜索,找到了即停止搜索,没找到则抛出NameError。前面作用域变量会屏蔽后面作用域的同名变量。

print(id(123)) #built-in
id='Global' #gloabl

def outside():
    id="Enclosing" #enclosing
    def inside():
        id="Local"  #local
        print(id)
    inside()
outside()
#输出
8790746362320
Local

global

  • 全局变量是在外层模块文件的顶层被赋值的变量名。
  • 全局变量如果是在函数内被赋值的话,必须经过global声明。
  • 全局变量名在函数的内部不经过声明也可以被引用。
g=18
def f3():
    g=19
    print(g)
f3()
print(g)
19
18

添加global声明后,函数内部不会生成一个新的名称为g的局部变量。

g=18
def f3():
    global g
    g=19
    print(g)
f3()
print(g)
19
19

nonlocal

如果想在内层作用域中修改外层所引用的对象,可以用nonlocal对变量声明。
使用nonlocal可以提供一个状态信息,如函数的调用次数等。

def tester(start):
    state=start
    def nested(label):
        nonlocal state
        print(label,state)
        state+=1
    return nested

F=tester(0)
F('spam')
F('ham')
F('egg')
#输出
spam 0
ham 1
egg 2

考虑到嵌套函数的复杂性,我们将在后续的闭包以及装饰器中继续介绍嵌套函数。