名称空间与作用域
一 名称空间
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