撤销'global <var>'语句

2 投票
3 回答
1651 浏览
提问于 2025-04-16 05:24

我正在学习Python,刚好有个问题想问。这个问题可能没有什么实际意义,我只是出于好奇想了解一下。

我有一个函数:

def f():
    x = 12    #this is a local variable
    global x  #this is a global I declared before
    x = 14    #changes global x

    <How can I return the local x?>

我知道这样写很糟糕,而且会收到语法警告。我只是想知道怎么才能“找回”我的局部变量。

谢谢大家。

3 个回答

1

不能撤销global语句的效果。

global语句在它出现的整个函数运行期间都有效,不管它在函数中的位置,也不管它是否被执行。因此,在下面这个函数的赋值中:

def f():
    x = 3
    if False:
        global x

x依然被视为全局变量。

所以在后面再加一个语句来撤销它的效果是没有意义的,因为global语句并不是在函数执行的某个时刻被执行的,而是对整个函数行为的一种声明。

4

我非常怀疑这件事能做到。

>>> x = 1
>>> def f():
...     x = 12
...     global x
...     print x
... 
<stdin>:3: SyntaxWarning: name 'x' is assigned to before global declaration
>>> f()
12
>>> x
12

如你所见,即使在global关键字后没有明确给x赋值,python还是会把这两个值同步起来。要理解原因,你需要对它进行拆解。

>>> dis.dis(f) # different f with print statement removed for clarity
  2           0 LOAD_CONST               1 (12)
              3 STORE_GLOBAL             0 (x)

  3           6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        
>>> 

这里根本没有显示global关键字,但赋值语句被编译成了STORE_GLOBAL。一旦你执行了这个操作,就完成了。使用全局变量要小心,使用global关键字更要谨慎。

7

你的代码并没有按照你想的那样运行,而且也没有办法让它按照你描述的那样去做。你不能“恢复”globals的功能,因为它在运行时没有任何效果。

global这个关键词是在编译时被解释的,所以在f()的第一行你设置x = 12时,这实际上是在修改全局的x。因为编译器已经决定了,x在整个函数中都指的是全局命名空间里的x,而不仅仅是在global语句之后。

你可以很简单地测试这一点:

>>> def g():
...     x = 12
...     y = 13
...     global x
...     print "locals:",locals()
...
<stdin>:4: SyntaxWarning: name 'x' is assigned to before global declaration
>>> g()
locals: {'y': 13}

locals()函数可以让我们查看局部命名空间,我们可以看到里面没有x这个变量。

文档中说了以下内容

global语句中列出的名字,不能在同一个代码块中出现在这个global语句之前。

global语句中列出的名字,不能被定义为正式参数,或者在for循环控制目标、class定义、函数定义或import语句中使用。

当前的实现并没有强制执行后面两个限制,但程序不应该滥用这种自由,因为未来的实现可能会强制执行这些限制,或者默默地改变程序的含义。

只需给局部变量起个不同的名字就可以了。

撰写回答