为什么Python中的函数可以打印封闭作用域的变量,但不能在赋值中使用它们?

36 浏览
0 Comments

为什么Python中的函数可以打印封闭作用域的变量,但不能在赋值中使用它们?

如果我运行以下代码:

x = 1
class Incr:
    print(x)
    x = x + 1
    print(x)
print(x)

它会打印:

1
2
1

好的,没有问题,这正是我预期的结果。如果我执行以下操作:

x = 1
class Incr:
    global x
    print(x)
    x = x + 1
    print(x)
print(x)

它会打印:

1
2
2

也是我预期的结果。没有问题。

现在如果我按照如下方式创建一个递增函数:

x = 1
def incr():
    print(x)
incr()

它会打印出1,正如我所预期的那样。我认为它这样做是因为在其局部作用域中找不到x,所以它会搜索其封闭的作用域并找到那里的x。到目前为止没有问题。

现在如果我执行以下操作:

x = 1
def incr():
    print(x)
    x = x + 1
incr()

这将在回溯中给我以下错误:

UnboundLocalError: local variable 'x' referenced before assignment.

为什么Python在找不到x的值进行赋值时不仅仅搜索封闭的作用域,就像我的class Incr一样?请注意,我不是在问如何使此函数工作。我知道如果我执行以下操作,该函数将正常工作:

x = 1
def incr():
    global x
    print(x)
    x = x + 1
    print(x)
incr()

这将正确打印:

1
2

正如我所预期的那样。我只是想知道为什么当关键字global不存在时,解释器不会从封闭作用域中获取x,就像它在上面的类示例中所做的那样。为什么解释器觉得有必要将其报告为UnboundLocalError,当它显然知道某个x存在。由于函数能够读取打印的x的值,我知道它将x作为其封闭作用域的一部分...那么为什么这样做与类示例中使用x的值进行赋值如此不同呢?我就是搞不懂。

0
0 Comments

为什么Python中的函数可以打印封闭作用域中的变量,但不能在赋值中使用这些变量?

Python遵循的是这样的规则——习惯就好了;-) 这其中有一个实际的原因:编译器和人类读者只需要查看函数本身,就可以确定哪些变量是局部变量。哪些变量是局部变量与函数所在的上下文无关。遵循这样的规则通常是一个非常好的主意,因为这样可以减少需要查看的源代码量。

关于:

我认为这是因为函数在其局部作用域中找不到x,所以会在其封闭作用域中进行查找并找到x。

并不完全正确:编译器在编译时就确定了哪些变量是局部变量,哪些变量不是局部变量。运行时并没有进行动态的“嗯,这是局部变量还是全局变量?”的搜索。具体规则可以在这里找到。

至于为什么不需要声明一个变量为global就可以引用其值,我喜欢Fredrik Lundh在这里的老回答。实际上,这样做确实很有价值,因为global语句可以提醒代码读者函数可能会重新绑定一个全局变量。

0
0 Comments

在Python的作用域和命名空间中,函数能够打印封闭作用域中的变量,但不能在赋值中使用这些变量。这个问题的出现原因是Python的作用域是在静态时确定的,即在函数被调用之前。因此,对于赋值语句x = x + 1,'x'被确定为一个局部变量,而不是全局变量。

同样的原因也导致在函数中禁止使用from mod import *。因为解释器在编译时不会为您导入模块,无法在运行时知道函数中使用的变量名。换句话说,在编译时必须知道函数中引用的所有变量名。

解决这个问题的方法是使用global关键字将变量声明为全局变量,以便在函数内部进行赋值操作。这样,函数就能够使用封闭作用域中的变量进行赋值。例如:global x

总结起来,Python中函数能够打印封闭作用域中的变量,但在赋值中不能使用这些变量的原因是作用域是在静态时确定的。解决方法是使用global关键字将变量声明为全局变量。

0
0 Comments

Python中的函数可以打印封闭作用域中的变量,但无法在赋值中使用它们。这是因为类和函数在变量的作用域方面有所不同。类中的变量实际上被分配给类的命名空间作为其属性,而函数中的变量只是普通的变量,无法在函数外部访问。

函数中的局部变量实际上是在函数第一次解析时确定的,Python不会在全局范围内搜索它们,因为它知道您将其声明为局部变量。因此,一旦Python看到一个赋值语句,并且该变量没有在全局或其他作用域中声明为全局变量,Python将不会在其他作用域中查找该变量。

但是,当您使用global语句时,Python将在全局作用域中查找该变量。对于嵌套函数,您可以在Python 3.x中使用nonlocal语句来修改在封闭函数中声明的变量。

然而,类的工作方式不同,类A中声明的变量x实际上变成了A.x。您还可以直接从全局范围访问类属性。在类中使用global语句会修改全局变量,而不是创建类属性。

函数的问题在类中不会引发错误。在类中,如果没有使用global和nonlocal语句,Python将按照LEGB规则进行搜索。LEGB规则的顺序是:Local(局部)、Enclosing(封闭)、Global(全局)和Built-ins(内置)。

函数无法在赋值中使用封闭作用域中的变量的原因是因为它们被视为局部变量,而类中的变量则被视为类的属性。要解决此问题,可以使用global语句声明变量为全局变量,或者在嵌套函数中使用nonlocal语句来修改封闭函数中的变量。

0