Python - 在先前已在全局范围内查找的函数内重新分配名称

标签 python

为什么我在下面的第三个代码中出错,但在前两个代码中却没有?我正在使用 Python 3.6.0、Anaconda 4.3.1(64 位)Jupyter。

代码 1:

c = 100
def fib():
    c = 20
    a = c
    print ("a in fib", a)
    print ("c in fib", c)
fib()
print ("c", c)

代码 1 的输出:

a in fib 20
c in fib 20
c 100

代码 2:

c = 100
def fib():
    a = c
    print ("a in fib", a)
    print ("c in fib", c)   
fib()
print ("c", c)

代码 2 的输出:

a in fib 100
c in fib 100
c 100

代码 3:

c = 100
def fib():
    a = c
    print ("a in fib", a)
    print ("c in fib", c)
    c = 20  
fib()
print ("c", c)

代码 3 的输出:


UnboundLocalError                         Traceback (most recent call last)
<ipython-input-42-d6affa26dc65> in <module>()
      7 
      8 
----> 9 fib()
     10 print ("c", c)

<ipython-input-42-d6affa26dc65> in fib()
      1 c = 100
      2 def fib():
----> 3     a = c
      4     print ("a in fib", a)
      5     print ("c in fib", c)

UnboundLocalError: local variable 'c' referenced before assignment

最佳答案

这种行为称为词法作用域。这里是官方的相关部分Python docs (强调我的):

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.

而对于"name binding operations"的定义(再次强调我的):

Names refer to objects. Names are introduced by name binding operations.

The following constructs bind names: formal parameters to functions, import statements, class and function definitions (these bind the class or function name in the defining block), and targets that are identifiers if occurring in an assignment, for loop header, or after as in a with statement or except clause. The import statement of the form from ... import * binds all names defined in the imported module, except those beginning with an underscore. This form may only be used at the module level.

A target occurring in a del statement is also considered bound for this purpose (though the actual semantics are to unbind the name).

因此,在您的第 3 个代码示例中, block 末尾的 c = 20 通过“如果出现在赋值中则为标识符的目标”子句作为名称绑定(bind)操作。这使得该函数中出现的所有 c 都引用 local 变量 c。但是,在运行时,您的代码首先命中 a = c 行。由于 c 实际上尚未在本地范围内定义,因此您会得到异常。

在第一个 block 中,您在尝试引用它之前在本地定义了 c,所以没有问题。

在第二种情况下,您不会在函数内对 c 执行任何名称绑定(bind)操作,因此 Python 假定您需要外部定义。

至于为什么它以这种方式工作,请参阅 this question :

The rationale for lexical scoping is not just for performance (full lexical scoping including closures actually has a performance cost, see the funcarg problems), it's for simplicity and reliability. While it may be surprising when first learning the language, the rules are actually dead simple so an experienced programmer can instantly tell which use of an identifier refers to which scope. One can understand functions in isolation, as execution isn't affected by who calls this functions and how they decided to name their variables.

关于Python - 在先前已在全局范围内查找的函数内重新分配名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43231598/

相关文章:

python - Pandas 列列表中每行的第一个非空值

python - 属性错误 : 'function' object has no attribute 'upper'

python - 如何使用正则表达式替换Python字典中的字符串

python - 从 Python 中的集合中选择一个项目

python - 在 python 上使用希伯来语

python - Pandas 滚动相关计算中的数值稳定性问题

python - 将 Python 字节码重新组装成原始代码?

python - 手动重新加载 Tornado

java - 语言查询和字数统计开源库 (LIWC)

python - 使用整数参数运行脚本