Python命名空间详解:内置、全局、闭包与本地命名空间的生命周期

1. 命名空间

Python命名空间详解:内置、全局、闭包与本地命名空间的生命周期

Python 程序在运行时,会依据需求创建命名空间。从命名空间的生命周期这个角度进行划分的话,可以把命名空间分成 4 种。

内置有全局闭包的本地的 1.1 内置命名空间。

内置空间保存着 Python 内置的变量对象,像 print 函数、list 对象等。Python 解释器创建和销毁内置命名空间。只要 Python 程序在运行,内置空间的变量就生效。例如:任何时候都能调用 print 函数,也能使用 list 创建列表。

内置空间的变量都保存在变量__builtins__里,能够通过使用 dir(__builtins__) 去查看其中所包含的内容。

In [1]: dir(__builtins__)
Out[1]:
['ArithmeticError',
 'AssertionError',
 'AttributeError',
 ...
 '__name__',
 '__package__',
 ...
 'print',
 'property',
 'range']

可以看到保存了一些内容,其中有内置的函数,如 print、range、tuple;有内置变量,像 __name__、__doc__;还有通用的异常,例如 TypeError。

1.2 全局命名空间

全局命名空间包含主程序中所定义的各种名称。Python 在主程序体开始运行时会创建全局命名空间,并且该命名空间会一直存在,直至解释器终止。它包含了在 py 文件中定义的内容以及从其他模块导入的内容。

为了更好地理解这个概念,举一个例子。创建一个名为 namespace.py 的文件。

from random import randint
VAR 被定义为“全局变量”。
class Demo:
    def __init__(self):
        pass
def func():
    print('function')
print(globals())

执行 python namespace.py 这个操作,接着执行 print(globals())语句,这样就能够将当前的全局变量打印出来。结果呈现如下。

这个程序的主名称是 '__main__' 。
 '__doc__': None, 
 '__package__': None, 
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000024E79813970>, 
 '__spec__': None, 
'annotations' 的值为空字典。
 '__builtins__': , 
'__file__' 的值为 'c:\\Users\\Documents\\demo\\namespace.py'
 '__cached__': None, 
 'randint': >, 
“VAR”指的是“全局变量”。
 'Demo': , 
 'func': }

可以看到,从 random 模块 import 的函数 randint 被加入到了 golbal 命名空间中。

1.3 本地和闭包命名空间

每当一个函数开始执行时,解释器会创建一个新的命名空间。这个命名空间就是函数的本地命名空间。当函数执行结束并返回后,这个本地命名空间就会被销毁。

在函数中若再次定义函数,那么对于外层函数而言,其本地命名空间就成为了内层函数的闭包命名空间。

下面通过一个例子来说明

定义一个名为 outter 的函数,该函数接收一个参数 arg。在 outter 函数内部定义一个变量 var 以及一个函数 inner。这个 inner 函数接收一个参数 a,并且在 inner 函数内部也定义一个变量 var。

In [1]: def outter(arg):
var 的值为“enclosing”。
   ...:     def inner(a):
var 等于 'inner var' 。
打印出“内部局部变量:”,并打印出局部变量的信息。
inner 表示“内部变量”。
打印出“外局部变量:”,然后打印出局部变量的信息。
   ...:
在[2]中:调用了 outter 函数并传入了 'param' 作为参数。
inner locals 包含两个键值对,一个键为 'a',值为 'inner var';另一个键为 'var',值也为 'inner var'。
外局部变量:{“arg”:“param”,“var”:“封闭的”,“inner”:}.inner 位于 0x00000202B37C8558 处>}

执行之后能看到,在 inner 函数中,其本地命名空间 locals 包含了变量 a 和 var 。在 outter 函数中,其本地命名空间 locals 包含变量 arg、var 以及函数 inner 。outter 函数的本地命名空间就是 inner 函数的闭包命名空间。

2. 变量作用域

多个命名空间会导致同一个变量名称能在多个命名空间中存在,且指向不同的对象,它们彼此互不干扰。当同一变量在不同的命名空间中存在时,Python 会按照 Local > Enclosing > Global > Built-in 的顺序进行搜索,如果最终仍未找到对应的对象,就会抛出 NameError 异常。

以下用几个实例来展示变量的搜索过程。变量 var 在函数 inner、函数 outter 和全局作用域中均有定义。执行函数 outter()以运行其中的 inner 函数后,print 语句首先在本地作用域中查找 var 所引用的对象,然后将其打印出来,结果为 inner var。

当函数 inner 中未定义 var 时,会降级到 inner 函数的闭包作用域(也就是 outter 函数的本地作用域)去进行查找,打印出来的结果为 enclosing

当函数 outter 中未定义 var 时,会降级到全局作用域去查找,此时 print 出来的是全局变量 global

修改外部命名空间中的变量。具体来说,对于可变对象,例如 list 和 dict 等。

对于可变对象,在内部作用域中会引用到外部对象。这种引用情况下,对对象的修改会直接作用到该对象本身。

In [1]: 数组为 ['adobe', 'abandon', 'aladdin']
In [2]: def modify():
array 加入了 'ariza' 。
In [3]: modify()
In [4]: array

3.2 不可变对象 如:int, string

正常情况下, 函数修改不了作用域外的不可变对象.

In [1]: var = 100
In [2]: def func():
   ...:     var = 200
   ...:     print(var)
In [3]: func()
200
In [4]: var
Out[4]: 100

3.3 使用global 和nonlocal

要修改作用域外的变量,能够使用 global 来声明变量为全局变量。当使用 global 将 var 声明为全局变量后,在函数 func 内对 var 进行修改,就会改变全局变量 var 的值。

In [1]: var = 100
In [2]: def func():
   ...:     global var
   ...:     var = 200
   ...:     print(var)
In [3]: func()
200
In [4]: var
Out[4]: 200

nonlocal 的使用方式是类似的。不同之处在于,nonlocal 会将变量声明为可修改闭包作用域中的变量。

In [1]: def outter():
   ...:     var = 'enclosing'
   ...:     def inner():
   ...:         nonlocal var
   ...:         var = 'inner var'
   ...:     inner()
   ...:     print(var)
In [2]: outter()
inner var

从上述代码可以看出,在 inner 函数中把 var 声明为 nonlocal 。当运行 inner()函数之后,outter 函数中的 var 被修改为“inner var”。

可以理解为 nonlocal 和 global 把处于当前作用域之外的变量拿到了本地作用域来使用。

若要修改作用域外的数据且对象为不可变对象,需使用 nonlocal 和 global 声明后才可修改本地命名空间的数据。

你可能想看:
« 上一篇
下一篇 »

相关推荐

python爬虫教程PDF,Python爬虫书PDF

2026年09月02日

31阅读

外国教程python,python编程教学视频

2026年09月02日

26阅读

python简明教程沈洁元,python详细基础教程

2026年09月02日

21阅读

python库包教程,python 包

2026年09月02日

27阅读

python教程大全集,python教程600集

2026年09月02日

27阅读

python入门教程完整版,python零基础入门全套教程视频

2026年09月02日

23阅读