python中的名称空间以及作用域分析

从Python解释器开始执行之后,就在内存中开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读入内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

名称空间:存放名字与内存地址关系的一个空间

全局名称空间:在python代码运行时就创建的变量名与内存地址对应关系的空间

局部名称空间:函数或类在运行时临时开辟出来的内存空间

作用域:作用域就是能够起作用的范围(如变量名被引用)

在python中,作用域分为全局作用域局部作用域

全局作用域:包含内置名称空间以及全局名称空间,在python文件中任意位置都能被引用,全局有效。

局部作用域:局部名称空间,只在局部有效,如函数,类等

作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关

名称空间的加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

名称空间的取值顺序:局部命名空间->全局命名空间->内置命名空间

global:

声明一个全局变量。
在局部作用域中想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。
def func():
    global a  #没有则创建一个全局变量
    a = 3
func()
print(a)  #3


count = 1
def search():
    global count
    count = 2
search()
print(count)  #2

def foo():
    a = 1
    def bar():
        global a
        print(a)
    bar()
foo()  #报错  name 'a' is not defined
#这是由于foo中的a不是全局作用域中的变量,那么在bar中重新创建了一个全局变量a,但是没有给a赋值,所以爆出这个错误

#对可变数据类型(list,dict,set)可以直接引用不用通过global,但是不能对改变它的内存地址,可以增加、删除,但`l1=l1[1:3]`时,这样就修改了原来的内存地址,所以会报错。
li = [1,2,3]
dic = {'a':'b'}

def change():
    li.append('a')
    dic['q'] = 'g'
    print(dic)
    print(li)
change()
print(li)
print(dic)

nonlocal:

不能修改全局变量。
在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
def add_b():
    b = 42
    def do_global():
        b = 10
        print(b)    #10 --------->1
        def dd_nonlocal():
            nonlocal b
            b = b + 20
            print(b)  #30
        dd_nonlocal()
        print(b)  #30 -------------2
    do_global()
    print(b)  #42
add_b()
#由于dd_nonlocal中声明的变量是从do_global中引用来的,所以在函数do_global中以及里面嵌套的函数中,都是相同的变量b,同时代码是从上到下执行,所以1出的b还没改变,还是10,但是2处的b已经改变了

a = 1
def foo():
    print(a)
    def bar():
        nonlocal a
        print(a)
    bar()
foo()  #SyntaxError: no binding for nonlocal 'a' found
#报错是由于nonlocal只能定义局部变量,此时的a是全局变量,所以报错

globals():查看全局作用域中的变量

locals():查看当前作用域中的变量

同时需要注意,在局部作用域中只能对全局变量进行引用,但是不能修改,这个修改只指的是不能对被引用的变量的内存地址进行改变,