为什么写入变量会改变其范围?
Why does writing to a variable change its scope?
采用以下代码示例
var = True
def func1():
if var:
print("True")
else:
print("False")
# var = True
func1()
这会打印 True
正如人们所期望的那样。
但是,如果我取消注释 # var = True
,我会得到错误
UnboundLocalError: local variable 'var' referenced before assignment
为什么写入变量会使原本可访问的变量无法访问?这种设计选择背后的基本原理是什么?
注意我知道如何解决它(使用 global
关键字)。我的问题是为什么它决定这样做。
因为:
命名空间存在:同一个变量名可以在模块级和函数内部使用,互不相关
Python不需要声明变量,方便使用
还需要一种方法来区分局部变量和全局变量
在可能出现意外行为的情况下,抛出错误比默默接受更好
所以Python选择了规则“如果一个变量名在一个函数中被赋值,那么这个名称指的是一个局部变量”(因为如果它从未被赋值,它显然不是局部变量,因为它永远不会得到一个值)。
您的代码可能 被解释为首先使用模块级变量(在 if: 行中),然后在稍后使用局部变量进行赋值。 但是,这通常不是预期的行为。所以 Guido 决定 Python 不会那样工作,而是抛出错误。
部分中有描述
When a name is not found at all, a NameError
exception is raised. If the current scope is a function scope, and the name refers to a local variable that has not yet been bound to a value at the point where the name is used, an UnboundLocalError
exception is raised. UnboundLocalError
is a subclass of NameError
.
If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.
Python 默认为通过赋值进行隐式变量声明,以消除对额外显式声明的需要。只是“隐式声明”留下了几个选项,嵌套范围中的赋值意味着什么,最突出的是:
- 赋值总是在最内层的范围内声明一个变量。
- 赋值总是在最外层作用域中声明一个变量。
- 赋值在最内层作用域中声明一个变量,除非在任何外部作用域中声明。
- 赋值在最内层作用域中声明一个变量,只有在赋值后才可读。
后两个选项意味着变量没有仅由赋值本身明确定义的范围。它们是“通过赋值声明 + X”,这可能导致不相关代码之间的意外交互。
剩下的决定是“写入变量”最好发生在孤立的 local 还是共享的 global 变量上。
Python 设计者认为显式标记写入全局变量更为重要。
Python FAQ: Why am I getting an UnboundLocalError when the variable has a value?
[...]
This explicit declaration is required in order to remind you that (...) you are actually modifying the value of the variable in the outer scope
这是对纯粹阅读全局变量的故意不对称,这被认为是正确的做法。
Python FAQ: What are the rules for local and global variables in Python?
[...]
On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time.
如果在嵌套作用域中使用在外部作用域中定义的变量名,则取决于您在该嵌套作用域中如何处理它:
如果你只读取一个变量,它是同一个变量。
如果你写到一个变量,那么Python会自动创建一个新的本地变量,与外层作用域不同
此局部变量阻止访问外部作用域中同名的变量。
所以写入一个变量不会改变它的范围,它会创建一个不同的局部变量。
您无法在分配给此局部变量之前读取它。
采用以下代码示例
var = True
def func1():
if var:
print("True")
else:
print("False")
# var = True
func1()
这会打印 True
正如人们所期望的那样。
但是,如果我取消注释 # var = True
,我会得到错误
UnboundLocalError: local variable 'var' referenced before assignment
为什么写入变量会使原本可访问的变量无法访问?这种设计选择背后的基本原理是什么?
注意我知道如何解决它(使用 global
关键字)。我的问题是为什么它决定这样做。
因为:
命名空间存在:同一个变量名可以在模块级和函数内部使用,互不相关
Python不需要声明变量,方便使用
还需要一种方法来区分局部变量和全局变量
在可能出现意外行为的情况下,抛出错误比默默接受更好
所以Python选择了规则“如果一个变量名在一个函数中被赋值,那么这个名称指的是一个局部变量”(因为如果它从未被赋值,它显然不是局部变量,因为它永远不会得到一个值)。
您的代码可能 被解释为首先使用模块级变量(在 if: 行中),然后在稍后使用局部变量进行赋值。 但是,这通常不是预期的行为。所以 Guido 决定 Python 不会那样工作,而是抛出错误。
When a name is not found at all, a
NameError
exception is raised. If the current scope is a function scope, and the name refers to a local variable that has not yet been bound to a value at the point where the name is used, anUnboundLocalError
exception is raised.UnboundLocalError
is a subclass ofNameError
.If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.
Python 默认为通过赋值进行隐式变量声明,以消除对额外显式声明的需要。只是“隐式声明”留下了几个选项,嵌套范围中的赋值意味着什么,最突出的是:
- 赋值总是在最内层的范围内声明一个变量。
- 赋值总是在最外层作用域中声明一个变量。
- 赋值在最内层作用域中声明一个变量,除非在任何外部作用域中声明。
- 赋值在最内层作用域中声明一个变量,只有在赋值后才可读。
后两个选项意味着变量没有仅由赋值本身明确定义的范围。它们是“通过赋值声明 + X”,这可能导致不相关代码之间的意外交互。
剩下的决定是“写入变量”最好发生在孤立的 local 还是共享的 global 变量上。
Python 设计者认为显式标记写入全局变量更为重要。
Python FAQ: Why am I getting an UnboundLocalError when the variable has a value?
[...]
This explicit declaration is required in order to remind you that (...) you are actually modifying the value of the variable in the outer scope
这是对纯粹阅读全局变量的故意不对称,这被认为是正确的做法。
Python FAQ: What are the rules for local and global variables in Python?
[...]
On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time.
如果在嵌套作用域中使用在外部作用域中定义的变量名,则取决于您在该嵌套作用域中如何处理它:
如果你只读取一个变量,它是同一个变量。
如果你写到一个变量,那么Python会自动创建一个新的本地变量,与外层作用域不同
此局部变量阻止访问外部作用域中同名的变量。
所以写入一个变量不会改变它的范围,它会创建一个不同的局部变量。
您无法在分配给此局部变量之前读取它。