返回顶部

python名称空间和作用域

一 名称空间

  • 名称空间就是存放名字和对象映射/绑定关系的地方,对于temp=3, python会申请内存空间存放对象3, 然后将temp与3的绑定关系存放与名称空间中, del x表示清除该绑定关系

  • 在程序执行期间最多会存在三种名称空间

1.1内置名称空间

  • 存放的名字: 存放的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
posted @ 2022-07-20 16:03  fuju  阅读(110)  评论(0)    收藏  举报