名称空间和作用域

1. 名称空间

名称空间,名称即名字,空间就是存放东西的地方。那么名称空间你可以理解为就是放名字的地方。我们之前说过

变量名是放在栈区的,变量值是放在堆区。这怎么又多出来个名称空间呢?我们慢慢来介绍。

实际上名称空间是对栈区的划分有了名称空间我们就可以在栈区中存放相同的名字了,名称空间让他们相互隔离

开来。进而也实现了资源隔离。名称空间是一种虚拟化的划分,栈区是真是存在的。

我们讲名称空间只考虑名字 , 是不考虑值的 , 因为名字太重要了 , 通过名字可以引用到值

image-20201123202914416

2. 三种名称空间

1.1 内置名称空间

存放python解释器内置的名字 , 比如 print input等

>>> print
<built-in function print>
>>> input
<built-in function input>

存活周期 :

python解释器启动则产生,python解释器关闭则销毁

1.2 全局名称空间

只要不是函数内定义、也不是内置的,剩下的都是全局名称空间的名字

import os  # os是存放在全局名称空间的名字

x = 123     # x是存放在全局名称空间的名字

def func():
    pass
func        # func是存放在全局名称空间的名字

存活周期 :

python文件执行则产生,python文件运行完毕后销毁

1.3 局部名称空间

在调用函数时,运行函数体代码过程中产生的函数内的名字

def func():
    x = 10
    y = 20
    
func()      # 函数调用就会产生x,y这两个名字,放在局部名称空间 函数结束,名字就会被销毁

存活周期 :

在调用函数时存活,函数调用完毕后则销毁

友情提示 :

# 函数的每次调用都会产生一个局部名称空间,哪怕是一个空函数,
# 或者一直调用同一个函数,也会每次都会产生不同的局部名称空间

3. 三种顺序

3.1 名称空间加载顺序

名称空间的加载顺序你也可以认为是名称空间的生成顺序

# 内置名称空间>全局名称空间>局部名称空间

3.2 名称空间销毁顺序

# 局部名称空间>全局名空间>内置名称空间

3.3 名字查找顺序

名字的查找顺序是以定义阶段为准的,从当前位置往外一层一层的找

# 当前所在的位置向上一层一层查找
 
# 内置名称空间  3层
# 全局名称空间  2层
# 局部名称空间  1层

# 这里的层是我个人抽象出来的

image-20201125151731595

# 如果当前在局部名称空间:
# 局部名称空间->全局名称空间->内置名称空间
# 如果当前在全局名称空间
# 全局名称空间->内置名称空间
# 举个栗子
x = 1


def func():
    print(x)  


def foo():
    x = 222
    func()


foo()       # 打印1

# 名称空间的"嵌套"关系是以函数定义阶段为准,与调用位置无关

x = 1


def foo():
    x = 222
    
    def func():
    	print(x)  
    func()


foo()    # 打印222

虽然函数的定义不会执行代码,但是会在函数内部搞一个名字,会先存个名字,等到调用的时候在会具体赋值

input = 111
def f1():
    def f2():
        print(input)
    input = 222
    f2()

input = 333
f1()        # 运行打印222

image-20201125161835781

4. 作用域

域是指范围的意思,作用域就是作用范围的意思

按照名字作用范围的不同可以将三个名称空间划分为两个区域: 全局作用域与局部作用域

4.1 全局作用域

全局作用域 : 位于全局名称空间、内置名称空间中的名字属于全局范围,该范围内的名字全局存活(除非被删除,

否则在整个文件执行过程中存活)、全局有效(在任意位置都可以使用);

# 特点: 全局存活
#      全局有效  被所有函数共享

4.2 局部作用域

局部作用域:位于局部名称空间中的名字属于局部范围。该范围内的名字临时存活(即在函数调用时临时生成,函

数调用结束后就释放)、局部有效(只能在函数内使用)。

# 特点: 临时存活
#      局部有效 : 函数内有效

4.3 locals和globals

# locals() 函数返回局部作用域中所有的名字
# globals() 函数返回全局作用域中所有的名字
# 返回的内容格式是字典格式

def func():
    x = 1
    print(locals())

func() # {'x': 1}

5. global和nonlocal

5.1 global

在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值

不可变类型时,则需要用到global关键字

name = "ymn"

def func():
    global name  # 把全局中的名字加载到局部内
    name = 'dl'  # 修改对应的值,这个值不会因为函数的结束,就销毁了,因为它作用到全局
    print(name)  # 打印 dl
    
func()        

print(name)     # name的值已经被修改了,所以打印 dl

5.2 nonlocal

nonlocal 会从当前函数的外层函数开始一层层去查找名字,若是一直到最外层函数都找不到,则会抛出异常。

nonlocal的查询边界就是最外面的一层函数。

x = 0


def func():
    x = 1

    def func2():
        nonlocal x
        x = 2

    func2()  # 调用fcun(),修改func作用域中名字x的值
    print(x)  # 在func作用域查看x


func()  # 结果2
print(x)  # 打印0  打印的是全局作用域中x的值
原文地址:https://www.cnblogs.com/xcymn/p/14518163.html