python名称空间和作用域
-
名称空间就是存放名字和对象映射/绑定关系的地方,对于temp=3, python会申请内存空间存放对象3, 然后将temp与3的绑定关系存放与名称空间中, del x表示清除该绑定关系
-
在程序执行期间最多会存在三种名称空间
-
存放的名字: 存放的python解释器内置的名字
-
存活周期: python解释器启动则产生, python解释器关闭则销毁
1.2 全局名称空间
-
存放的名字: 只要不是函数内定义, 也不是内置的, 剩下的都是全局名称空间的名字
-
存活周期: python文件执行则产生, python文件运行完毕后销毁
import sys # 模块名sys
x = 1 # 变量名x
if x == 1:
y=2 #变量名y
def foo(x): #函数名foo
y=1
def bar():
pass
Class Bar: # 类名Bar
pass
1.3 局部名称空间
-
随着函数的调用/结束而临时产生/回收, 函数的参数, 函数内定义的名字都会存放与局部名称空间
-
存活周期:在调用函数时存活,函数调用完毕后则销毁
def foo(x):
y=3 # 调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中
1.4 总结
-
全局名称空间: 我们直接py文件中, 函数外声明的变量都是属于全局命名空间
-
局部名称空间: 在函数中声明的变量会放在局部命名空间
-
内置名称空间: 存放python解释器为我们提供的名字, list,tuple,str int这些内置名称空间
1.5 加载顺序
-
在启动Python解释器的时候,就已经导入到内存当中供我们使用,所以肯定是先加载内置名称空间,然后就开始从文件的最上面向下一行一行执行,此时如果遇到了初始化变量,就会创建全局名称空间,将这些对应关系存放进去,然后遇到了函数执行时,在内存中临时开辟一个空间,加载函数中的一些变量等等。所以这三个空间的加载顺序为:内置命名空间(程序运行时加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载。
1.6 取值顺序
# 如果你在全局名称空间引用一个变量,先从全局名称空间引用,全局名#
# 称空间如果没有,才会向内置名称空间引用。
input = 666
print(input) # 666
# 如果你在局部名称空间引用一个变量,先从局部名称空间引用,
# 局部名称空间如果没有,才会向全局名称空间引用,全局名称空间在没有,就会向内置名称空间引用。
input = 666
print(input) # 666
input = 666
def func():
input = 111
print(input) # 111
func()
-
所以空间的取值顺序和加载顺序时相反的, 取值顺序满足的是就近原则, 从小范围到大范围一层一层引用
二 作用域
-
作用域就是作用范围, 按照生效范围来看分为全局作用域和局部作用域
-
全局作用域: 包含内置名称空间和全局名称空间, 在整个文件的任何地方都可以使用(遵循从下到上逐行执行) 全局有效
-
局部作用域: 在函数内部可以使用, 函数调用时生成, 函数解释后释放, 局部有效
-
2.1作用域名称空间:
-
全局作用域: 全局命名空间+ 内置命名空间
-
局部作用域: 局部名称空间
2.2 作用域与名字查找的优先级
-
在局部作用域查找名字时, 起始位置是局部作用域, 先找局部命名空间, 找不到,再去全局名称空间, 找不到, 在查找内置名称空间
x=100 # 全局作用域的名字x
def func():
x=300 # 局部作用域的名字x
print(x) # 在局部找x
func() # 结果为300
2.3 内置函数 globals(), locals()
-
globals(): 以字典的形式返回全局作用域所有的变量对应关系
-
locals() : 以字典的形式返回当前作用域的变量的对应关系
# 在全局作用域下打印,则他们获取的都是全局作用域的所有的内容。
a = 11
b = 22
print(globals())
print(locals())
"""
{'__name__': '__main__', '__doc__': '\n@作者: roc小白\n@ QQ: 845726666\n@专栏: https://www.cnblogs.com/jupeng/p/14939889.html\n',
'__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002B320DD3DC0>, '__spec__': None,
'__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/29/day15/名称空间和作用域.py', '__cached__': None,
'input': 666, 'a': 11, 'b': 22}
{'__name__': '__main__', '__doc__': '\n@作者: roc小白\n@ QQ: 845726666\n@专栏: https://www.cnblogs.com/jupeng/p/14939889.html\n',
'__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002B320DD3DC0>, '__spec__': None,
'__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/29/day15/名称空间和作用域.py',
'__cached__': None, 'input': 666, 'a': 11, 'b': 22}
"""
# 在局部作用域中打印。
a = 2
b = 3
def foo():
c = 3
print(globals()) # 和上面一样,还是全局作用域的内容
print(locals()) # {'c': 3}
foo()
"""
{'__name__': '__main__', '__doc__': '\n@作者: roc小白\n@ QQ: 845726666\n@专栏: https://www.cnblogs.com/jupeng/p/14939889.html\n', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000201B7BC3DC0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/29/day15/名称空间和作用域.py', '__cached__': None, 'input': 666, 'a': 2, 'b': 3, 'foo': <function foo at 0x00000201B7C0D280>}
{'c': 3}
"""
2.4 global 和 nonlocal 关键字
-
global: 在局部作用域中可以更改全局作用域的变量。 仅限数字和字符串
-
局部作用域对全局作用域的变量(此变量只能是不可变的数据类型)只能进行引用,而不能进行改变,只要改变就会报错
# 如果在局部想要修改全局的名字对应的值(不可变类型),需要用global
x = 111
def func():
global x # 声明x这个名字是全局的名字,不要再造新的名字了
x = 222
func()
print(x)
# 利用global 在局部作用域也可以声明一个全局变量
def func():
global a
a = 3
func()
print(a)
-
nonlocal
-
nonlocal 不能改变全局变量, 在局部作用域中, 对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
# nonlocal(了解): 修改函数外层函数包含的名字对应的值(不可变类型)
x = 1
def f1():
x=11
def f2():
nonlocal x
x=22
f2()
print('f1内的x:',x)
f1()
三. 函数的嵌套
# # 例1:
def func1():
print('in func1')
print(3)
def func2():
print('in func2')
print(4)
func1()
print(1)
func2()
print(2)
# 结果 in func1 3 1 in func2 4 2
# # 例2:
def func1():
print('in func1')
print(3)
def func2():
print('in func2')
func1()
print(4)
print(1)
func2()
print(2)
# 结果: 1 in func2 in func1 3 4 2
# 例3:
def fun2():
print(2)
def fun3():
print(6)
print(4)
fun3()
print(8)
print(3)
fun2()
print(5)
# 结果: 3 2 4 6 8 5