名称空间与作用域
1 名称空间(namespaces):
名称空间是存放各种名字的地方,是对栈区的一种划分
名称空间可以分为三种:
内置名称空间,全局名称空间,局部名称空间
有了名称空间之后,就可以在栈区中存放相同的名字, 而不会互相干扰
1.1 内置名称空间
内置名称空间存放的名字:python解释器内置的名字
内置名称空间的存活周期:python解释器启动则产生,python解释器关闭则销毁
>>> print
<built-in function print>
>>> input
<built-in function input>
1.2 全局名称空间
全局名称空间存放的名字:只要不是局部定义、也不是内置的,剩下的都是全局名称空间的名字
全局名称空间的存活周期:python文件执行则产生,python文件运行完毕后销毁
x=10
if 13 > 3:
y=20
if 3 == 3:
z=30
# func=函数的内存地址
def func():
a=111
b=222
class foo:
pass
# 其中x,y,z,func,foo都存放于全局名称空间
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) # input局部空间内有,使用局部空间的input
func()
# 查看局部空间的input是否定义了值----->444
# 444
input=333
def func():
print(input) # input局部空间内没有,全局空间内有,使用全局空间的input
func()
# 查看全局空间的input是否定义了值----->333
# 333
def func():
print(input)# input局部空间内没有,全局空间内也没有,内置空间有,使用内置空间的input
func()
# 查看内置空间的input是否定义了值-----><built-in function input>
# <built-in function input>
input=333
def func():
input=444
func()
print(input)# input全局空间内没有,内置空间有,使用内置空间的input
# 查看内置空间的input是否定义了值-----><built-in function input>
# 333
def func():
print(x)# x局部空间内没有,全局空间内有,使用全局空间的x
x=111
func()
# 查看内置空间的input是否定义了值-----><built-in function input>
# 111
# 注意:不会报错,若x=111在func()代码执行后,会报错,因为没定义x的值
# 名称空间的"嵌套"关系是以函数定义阶段为准,与调用位置无关
x=1
def func():
print(x) # x局部空间内没有,全局空间内有,使用全局空间的x
def foo():
x=222
func()
foo()
# 1在执行前定义了,不报错
# 结果: 1
input=111
def f1():
def f2():
print(input)# input局部空间f2()内没有,局部空间f1()内有,使用局部f1空间的input
input=222
f2()
f1()
# 222在执行前定义了,不报错
# 222
input=111
def f1():
def f2():
input=333
print(input)# input局部空间f2内有,使用局部f2空间的input
input=222
f2()
f1()
# 333在执行前定义了,不报错
# 333
input=111
def f1():
def f2():
print(input)# input局部空间f2()内没有,局部空间f1()内没有,全局空间内有,使用全局空间的input
f2()
f1()
# 111在执行前定义了,不报错
# 111
x=111
def func():
print(x) # x局部空间内有,使用局部空间的x
x=222
func()
# 使用局部空间的x输出,但是x还没定义,不能输出,报错
# UnboundLocalError: local variable 'x' referenced before assignment
2 作用域
作用域也就是作用范围,作用域可以分为两类: 全局作用域 和 局部作用域
2.1 全局作用域:
全局作用域包含内置名称空间与全局名称空间
特点:
1、全局存活
2、全局有效:被所有函数共享
x=111
def foo():
print(x,id(x))
def bar():
print(x,id(x))
foo()
# 111 140726763447392
bar()
# 111 140726763447392
print(x,id(x))
# 111 140726763447392
2.2 局部作用域
局部作用域包含局部名称空间的名字
特点:
1、临时存活
2、局部有效:函数内有效
def foo(x):
def f1():
def f2():
print(x)
f2()
f1()
foo(1)
# 1
# LEGB
# local 本地,最内层
# enclosing 外层嵌套
# global 全局
# builtin 内置
# global
def f1():
# enclosing
def f2():
# enclosing
def f3():
# local
pass
3 申明所在名称空间
如果我们想在局部修改外部的变量,
可以使用global或nonlocal方法申明变量所属的名称空间,
之后对这个名字的操作就不再是对本地local的名字进行操作,而是对申明的名字操作
x=111
def func():
x=222
func()
print(x)
# 111
3.1 global
global: 申明后,可以修改全局名称空间中包含的名字对应的值(不可变类型)
x=111
def func():
global x # 声明x这个名字是全局的名字,不要再造新的名字了
x=222
func()
print(x)
# 222
# 对于可变数据类型,没有必要申明global,不申明依旧可以修改全局名称空间中的l
l=[111,222]
def func():
l.append(333)
func()
print(l)
3.2 nonlocal
nonlocal: 申明后,可以修改函数外层函数包含的名字对应的值(不可变类型)
x=0
def f1():
x=11
def f2():
nonlocal x
x=22
f2()
print('f1内的x:',x)
f1()
# f1内的x: 22
# 对于可变数据类型,没有必要申明nonlocal,不申明依旧可以修改函数外层函数中的列表
def f1():
x=[]
def f2():
x.append(1111)
f2()
print('f1内的x:',x)
f1()
# f1内的x: [1111]