Python 作用域

这篇文章翻译自https://www.pythontutorial.net/advanced-python/python-variable-scopes/


Python 变量作用域

摘要:在这篇教程,你将学习 Python 作用域的工作原理。看完这篇教程,你将对内置,局部和全局变量有一个很好的理解。

变量作用域的介绍

当你把一个对象分配给一个变量时,该变量将在内存中引用该对象。这就是说,该变量被绑定到该对象。

赋值后,你可以在代码的许多部分使用该变量名来访问该对象。但是,你不能在所有代码中访问该变量。

变量名称和它的绑定(名称和对象)只存在于你代码的特定部分。

你定义名称/绑定的代码部分被称为变量的词法范围。

Python 将这些绑定存储在称为命名空间的东西中。每个作用域都有自己的命名空间。

你可以认为命名空间是一个表,它包含了标签和标签所绑定的引用。

全局作用域

全局作用域基本上就是模块作用域。全局作用域只跨越一个 Python 源代码文件。

除了内置作用域,Python 没有一个真正的全局作用域可以跨越所有的模块。

内置作用域是一个特殊的作用域,它提供全局可用的对象,如 print , len , None , True , 和 False

基本上,内置变量和全局变量存在于一个模块内部的任何地方。

在内部,全局作用域被嵌套在内置作用域中。

Python-Variable-Scopes.png

如果你从一个作用域访问一个变量,而 Python 在该作用域的命名空间中找不到它,它将在包围的作用域的命名空间中搜索。

假设你在一个名为 app.py 的模块中拥有以下语句。

print('Hello')

在这个 app.py 模块中,Python 在模块范围内寻找 print 函数 ( app.py )。

由于 Python 在 app.py 模块作用域中没有找到 print 函数的定义,Python 上升到包围作用域,也就是内置作用域,并在那里寻找 print 函数。在这种情况下,它可以在内置作用域中找到 print 函数。

Python-Built-in-Scope.png

如果你把语句改为以下内容,你会得到一个运行时错误。

print(counter)

在这个例子中,Python 在当前全局作用域中没有找到 counter 。因此,Python 在包围的作用域(内置作用域)中寻找它。

然而,变量 counter 并不存在于内置的作用域中。因此,Python 发布了一个 NameError 异常。

NameError: name 'counter' is not defined

局部作用域

当创建一个函数时,你可以为该函数定义参数和变量。例如:


def increment(counter, by=1):
    result = counter + by
    return result

当你执行代码时,Python带有两个阶段:编译和执行。(译者注:这里的编译阶段指的是将代码转换为字节码的过程,执行阶段指的是将字节码转换为机器码的过程。)

当 Python 编译文件时,它将 increment 函数添加到全局范围。此外,Python 决定 increment() 函数内的 counter by result 变量是 increment() 函数的局部变量。而且在函数执行之前,Python 不会创建 counter by result 变量。

每当你调用一个函数,Python 都会创建一个新的作用域。Python 也会把在函数中定义的变量分配给这个作用域。而这个作用域被称为函数局部作用域或局部作用域。

在我们的例子中,当你调用 increment() 函数时。

increment(10, 2)

…Python 为 increment() 函数的调用创建了一个局部作用域。

另外,Python在局部命名空间中创建了局部变量 counter by result ,并将它们与值 10 2 12 变量绑定。

当函数完成时,Python 将删除局部作用域。而所有的局部变量,如 counter by result 变量都超出了范围。(译者注:此处指函数执行完成时,局部变量被清除,并释放空间)如果你试图从 increment() 函数之外访问这些变量,你会得到一个错误。

而如果你再次调用 increment() 函数。

increment(100, 3)

Python创建了一个新的局部作用域和变量,包括 counter by result 并将它们与值 100 3 103 绑定。

变量查找顺序

在 Python 中,作用域是嵌套的。例如,局部作用域被嵌套在模块作用域中。而模块作用域是嵌套在内置作用域里面的。

Python-Nested-Scopes.png

当你访问一个与变量绑定的对象时,Python 会试图找到这个对象。

  • 首先在当前的局部作用域内查找。

  • 如果 Python 在当前作用域中没有找到该对象,就会沿着包围作用域的链条向上走。

全局关键字

当你从一个函数内部检索一个全局变量的值时,Python 会自动搜索本地作用域的名字空间,并向上搜索所有包围作用域的命名空间链。比如说:

counter = 10

def current():
    print(counter)

current()

在这个例子中,当 current() 函数运行时,Python 在局部作用域内寻找 counter 变量。

由于 Python 没有找到它,它就在全局作用域内搜索这个变量。而在这种情况下,Python可以找到 counter 变量。

然而,如果你从一个函数中给全局变量赋值,Python 将把这个变量放到局部命名空间中。比如说


counter = 10

def rset():
    counter = 0
    print(counter)

reset()
print(counter)

输出:

0

10

在编译时,Python 将 counter 解释为一个局部变量。

reset() 函数运行时,Python在局部范围内找到 counter 。在 reset() 函数内部的 print(counter) 语句显示了 counter 的值,它是0。

当我们在 reset() 函数完成后打印 counter 时,显示的却是10。

在这个例子中,局部 counter 变量掩盖了全局 counter 变量。

如果你想从一个函数内部访问一个全局变量,你可以使用 global 关键字。比如说

counter = 10

def reset():
    global counter
    counter = 0
    print(counter) # 0

reset()

print(counter) # 0

输出:

0

0

在这个例子中,下面的语句。

global counter

指示 Python 将 counter 变量绑定到全局作用域,而不是局部作用域。

请注意,在一个函数内访问全局变量不是一个好的习惯。

总结

  • 变量的作用域是你可以访问该变量的代码部分

  • 内置作用域的变量可以从任何地方访问。

  • 全局作用域(或模块作用域)可以从模块的每个部分访问。

  • 局部作用域可以从一个函数内部访问。

  • Python 在作用域的命名空间中存储对象和它们的绑定关系。

  • Python 首先在当前作用域中查找一个对象,如果 Python 没有找到它,就上升到包围的作用域。

  • Python的作用域是嵌套的。

  • 使用 global 关键字从一个函数内部访问一个全局变量。
    (全文完)

部分图片来自于源网站,侵删。

鉴于本人才疏学浅,翻译难免有所疏漏,如果有任何问题欢迎随时联系我进行批评指正:2076577077@qq.com

我是gled fish, 点击这里来到我的博客网站:


转载请注明译者和原出处,请勿用于任何商业用途。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值