Python 中的变量作用域定义了变量对于用户的可访问区域。变量的作用域取决于其定义的位置和方式。在 Python 中,变量可以具有全局作用域或局部作用域。
Python 变量的作用域分类
根据作用域,Python 变量可以分为三类:
局部变量
局部变量是在特定函数或代码块内定义的。它只能被定义它的函数或块所访问,并且其作用范围有限。换句话说,局部变量的作用域仅限于它们所在的函数,尝试在其外部访问它们会导致错误。始终记住,可以存在多个同名的局部变量。
示例
下面的示例展示了局部变量的作用域。
def myfunction():
a = 10
b = 20
print("变量 a:", a)
print("变量 b:", b)
return a + b
print(myfunction())
在上面的代码中,我们通过其函数访问了局部变量。因此,代码将产生以下输出:
变量 a: 10
变量 b: 20
30
全局变量
全局变量可以从程序的任何部分访问,并且定义在任何函数或代码块之外。它不属于任何特定的块或函数。
示例
下面的示例展示了全局变量的作用域。我们可以在函数内部以及外部访问它们。
name = 'TutorialsPoint'
marks = 50
def myfunction():
print("name:", name)
print("marks:", marks)
myfunction()
上述代码将产生以下输出:
name: TutorialsPoint
marks: 50
非局部变量
那些既不在局部也不在全局作用域内的 Python 变量被称为非局部变量。它们通常用于嵌套函数中。
示例
下面的示例演示了非局部变量的工作原理。
def yourfunction():
a = 5
b = 6
def myfunction():
nonlocal a
nonlocal b
a = 10
b = 20
print("变量 a:", a)
print("变量 b:", b)
return a + b
print(myfunction())
yourfunction()
上述代码将产生以下输出:
变量 a: 10
变量 b: 20
30
命名空间与 Python 变量的作用域
命名空间是一组标识符,例如变量名、函数名、类名等。在 Python 中,命名空间用于管理变量的作用域,并防止命名冲突。
Python 提供了以下几种类型的命名空间:
-
内置命名空间包含内置函数和异常。它们在 Python 解释器加载时就存在于内存中,并持续到解释器运行结束。
-
全局命名空间包含主程序中定义的所有名称。这些名称在程序运行期间一直存在于内存中。
-
局部命名空间包含函数内部定义的名称。它们在函数运行期间可用。
这些命名空间是嵌套的,一个在另一个里面。下面的图展示了命名空间之间的关系。
变量的生命周期
某个变量的生命期限制在其定义的命名空间内。因此,不可能从外部命名空间访问内部命名空间中的变量。
Python 的 globals() 函数
Python 标准库中包含一个内置函数 globals()
。它返回当前在全局命名空间中的符号字典。
直接从 Python 提示符运行 globals()
函数。
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
可以看到,包含所有内置函数和异常定义的内置模块已经被加载。
示例
保存以下代码,其中包含几个变量和一个函数,函数内部也有几个变量。
name = 'TutorialsPoint'
marks = 50
result = True
def myfunction():
a = 10
b = 20
return a + b
print(globals())
从脚本内部调用 globals()
返回以下字典对象:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000263E7255250>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:\\Users\\user\\examples\\main.py', '__cached__': None, 'name': 'TutorialsPoint', 'marks': 50, 'result': True, 'myfunction': <function myfunction at 0x00000263E72004A0>}
全局命名空间现在包含了程序中的变量及其值和函数对象(而不是函数内的变量)。
Python 的 locals() 函数
Python 标准库中包含一个内置函数 locals()
。它返回当前在函数局部命名空间中的符号字典。
示例
修改上述脚本以从函数内部打印全局和局部命名空间的字典。
name = 'TutorialsPoint'
marks = 50
result = True
def myfunction():
a = 10
b = 20
c = a + b
print("globals():", globals())
print("locals():", locals())
return c
myfunction()
输出显示 locals()
返回了函数当前可用的变量及其值的字典。
globals(): {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000169AE265250>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:\\Users\\mlath\\examples\\main.py', '__cached__': None, 'name': 'TutorialsPoint', 'marks': 50, 'result': True, 'myfunction': <function myfunction at 0x00000169AE2104A0>}
locals(): {'a': 10, 'b': 20, 'c': 30}
由于 globals()
和 locals
函数返回的是字典,你可以使用字典的 get()
方法或索引操作符来从相应的命名空间中访问变量的值。
print(globals()['name'])
print(locals().get('a'))
Python 中的命名空间冲突
如果全局和局部作用域中存在同名变量,Python 解释器会优先处理局部命名空间中的变量。
示例
在下面的示例中,我们定义了一个局部变量和一个全局变量。
marks = 50
def myfunction():
marks = 70
print(marks)
myfunction()
print(marks)
它将产生以下输出:
70
50
示例
如果你试图在函数内部修改全局变量的值,Python 会抛出 UnboundLocalError
如下面的示例所示:
marks = 50
def myfunction():
marks = marks + 20
print(marks)
myfunction()
print(marks)
它将产生以下错误信息:
marks = marks + 20
^^^^^
UnboundLocalError: cannot access local variable 'marks' where it is not associated with a value
示例
要修改全局变量,你可以使用字典语法更新它,或者在修改之前使用 global
关键字引用它。
var1 = 50
var2 = 60
def myfunction():
"更改全局变量的值"
globals()['var1'] = globals()['var1'] + 10
global var2
var2 = var2 + 20
myfunction()
print("var1:", var1, "var2:", var2)
执行代码后,它将产生以下输出:
var1: 60 var2: 80
示例
最后,如果你试图在全局作用域中访问局部变量,Python 会抛出 NameError
,因为局部作用域中的变量无法在其外部访问。
var1 = 50
var2 = 60
def myfunction(x, y):
total = x + y
print("Total 是一个局部变量:", total)
myfunction(var1, var2)
print(total)
它将产生以下错误信息:
Total 是一个局部变量: 110
Traceback (most recent call last):
File "C:\Users\user\examples\main.py", line 9, in <module>
print(total)
^^^^^
NameError: name 'total' is not defined