名称空间与作用域

一 名称空间

1、名称空间namespace

名称空间是存放名字(变量名与内存地址的绑定关系)的地方,是对栈区的划分,有了名称空间之后,就可以在栈区中存放相同的名字。

(栈区划分成多片名称空间,相当于把名字归类了,最大的好处是:当两个变量名相同时,可以存放在两个不同的名称空间,就不会冲突了)

名称空间分为三种:

​ 内置名称空间、全局名称空间、局部名称空间(多个)

名字----------------》相当于人

栈区-----------------》地球

名称空间-----------》国家

作用域--------------》国家的影响力

名称空间与作用域

Ps:名称空间只有优先级之分,本身并无嵌套关系

1.1 内置名称空间

​ 存放的名字:存放的是 python 解释器内置的名字

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

​ 存活周期:python 解释器启动则产生、python 解释器关闭则销毁

1.2 全局名称空间

​ 存放的名字:只要不是函数内定义,也不是内置的,剩下的都是全局名称空间的名字。

​ 存活周期:python 文件执行则产生,python文件运行完毕后则销毁

import os  #全局名称空间名字
x= 10    #全局名称空间名字
if 13 > 3:   
		y =20  #全局名称空间名字
		if 3==3:
			 z=30 #全局名称空间名字
#func = 函数的内存地址(函数名是全局名称空间的名字)
def func():
		a = 111
    b = 222

func()

1.3 局部名称空间

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

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

def func(a,b):
		pass
		
func(10, 1)

注:同一个函数,被调用多次,就会产生多个局部名称空间(哪怕没有函数体代码)

func(11, 12)
func(13, 14)
func(15, 16)

1.4 名称空间的加载顺序

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

1.5 名称空间的销毁顺序

局部名称空间 > 全局名称空间 > 局部名称空间

1.6 名字的查找优先级

大前提:当前所在的位置(先找当前空间)向上一层一层查找

​ 内置名称空间

​ 全局名称空间

​ 局部名称空间

如果当前在局部名称空间:

​ 局部名称空间---->全局名称空间----->内置名称空间

如果当前在全局名称空间

​ 全局名称空间 ---->内置名称空间

示例:

input=333
def func():
    input=444
    print('===>', input) #===> 444

func()
print(input) # 333

名称空间的'嵌套'关系是以函数定义阶段为准,与调用位置无关****(很重要)

即函数的嵌套关系与名字的查找顺序是在定义阶段就已经确定好的

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

函数嵌套定义

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

示范 4:

x = 111
def func():
  	print(x) #报错,x=222 在 print(x)下面
    x=222
func()

例题:

input=333
def func():
    input=444
func() 
print(input) #333

名称空间与作用域

def func():
    print(x)
x=111

func() #111

名称空间与作用域

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

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

名称空间与作用域

x=111

def foo():
    print(x,) #111

def bar():
    print(x)  #111

foo()
bar()
x=1
def func2():
  	print(x) #3
    func1()

x=2
def func1():
    print(x) #3

x=3

func2()
a1 = 1
def func():
    a1=3
    print(a1) #3
    a1=4
a1 = 2
func()

二 作用域

作用域---->作用范围

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

​ 全局作用域和局部作用域

全局作用域:内置名称空间 、全局名称空间

​ 1、全局存活

​ 2、全局有效:被所有函数共享

x = 111
def foo():
  	print(x,id(x))
def bar():
  	print(x, id(x))
    
foo()
bar()

局部作用域:局部名称空间的名字

1、临时 存活

2、局部有效:函数内有效

def foo():
		def f1():
				def f2():
						print(x)
LEGB
# builtin
# global
def f1():
    # enclosing
    def f2():
        # enclosing
        def f3():
            # local
            pass

三 global 与 nonlocal

global

示范 1:

x =111
def func():
    x=222

func()
print(x) #111

如果在局部内想要修改全局的名字对应的值(不可变类型),需要global

x = 111
def func():
  	global x #声明 x 这个名字是全局的名字,不要再造新的名字了
    x =222

func()
print(x) #222

当实参的值为可变类型时,函数体内对该值的修改将直接反应到原值

num_list = [1,2,3]
def foo(nums):
		nums.append(5)

foo(num_list)
print(num_list) #[1,2,3,5]

nonlocal(了解)

对于嵌套多层的函数,使用 nonlocal 关键字可修改函数的外层函数包含的名字对应的值(不可变类型)。

注意,这里只能修改包含名字的最近一层的外层函数对应的值

x = 0
def f1():
    x = 11
    def f2():
        x = 222
        def f3():
            nonlocal x
            x = 333
        f3()
        print('f2内的 x:', x) #f2内的 x: 333

    print('f1内的 x:', x)  # f1内的 x: 11
    f2()

f1()
结果展示:
f1内的 x: 11
f2内的 x: 333