在Python中解析全局作用域中的变量

3

我正在尝试更好地理解Python中的作用域。我有以下玩具示例:

a = 1
print "in global: " + str(a)

def g():
    a += 1
    print "in g(): " + str(a)


def f():
    a += 1
    print "in f(): " + str(a)
    g()

f()

我期望这段代码能够运行并打印出 1,然后是 2,最后再次是 2。但是,实际上我遇到了一个错误:

UnboundLocalError: local variable 'a' referenced before assignment

我原本认为 g()f() 都会从全局作用域中提取 a。这是不正确的吗?
更新: 感谢您的回答,但仍有不清楚的地方:如果我想读取全局变量 a 并将其分配给我创建的一个名为 a 的局部变量,这是否可行?
我这么做的原因是我试图弄清楚当调用 g() 时它是否继承了 f() 的作用域或定义它的全局作用域?
4个回答

5
您正在尝试更改外部作用域中的 aa 不在当前函数的作用域内,这就是为什么会出现此错误的原因,因为您的函数对 a 一无所知。如果您想从函数内部更改 a,则需要使用 `global':
a = 1
print "in global: " + str(a)

def g():  
    global a
    a += 1
    print "in g(): " + str(a)


def f():
    global a
    a += 1
    print "in f(): " + str(a)
    g()

要打印全局变量 a ,可以按照以下方式使用:

def f():
    print a
    new_a = a
    print new_a

这里有一个关于 global 的好例子,点击此处查看。

如果你想使用全局变量 a 的值来定义本地变量 a,请使用globals

def g():  
    a = globals()['a']
    a += 1
    print "in g(): " + str(a)

1
在你的第二段代码中,你不需要使用 global - gil

4
您需要使用global关键字。
>>> a = 1         
>>> def g():      
...     global a  
...     a += 1    
...     print a   
...               
>>> g()           
2    

4
您在g和f函数中缺少全局运算符,应该像这样编写代码:

a = 1

def g():
    global a
    a += 1
    print "in g(): " + str(a)

def f():
    global a
    a += 1
    print "in f(): " + str(a)

您可以在此处的文档Stack Overflow中找到有关全局变量和局部变量的更多信息。


1
当您请求变量值时,Python遵循LEGB规则:本地、封闭、全局、内置。
但是当您分配变量时,在本地范围内从头创建它(假设变量分配在函数内部),丢弃先前绑定到它的任何值。
a = 5
def f(x):
   print a  # Prints `5`, because name `a` can be found following LEGB rule in Global scope.
   print x  # Prints whatever value `x` was having, found following LEGB rule in Local scope.
   x = 123  # Forgets previous value of `x`, re-assign it to `123` in the Local scope.

您遇到的未绑定变量问题出现在这里:a += 1只是a = a + 1的一种语法糖。当您执行a = a + 1时,Python会捕获a是本地变量,并在字节码中生成LOAD_FAST命令:
import dis
a = 1
def f():
  a += 1
print dis.dis(f)

          0 LOAD_FAST                0 (a)
          3 LOAD_CONST               1 (1)
          6 INPLACE_ADD
          7 STORE_FAST               0 (a)
         10 LOAD_CONST               0 (None)
         13 RETURN_VALUE

LOAD_FAST用于获取本地变量。但是当调用LOAD_FAST时,本地范围内尚未有a,因此该命令失败。

实际上,如果您不对a进行赋值,但想要从本地范围修改它,可以通过方法调用来完成。不幸的是,int没有修改方法,因此我将用类举例说明:

class Number(object):
    def __init__(self, x):
        self.x = x
    def add_one(self):
        self.x += 1

a = Number(1)
def f():
    a.add_one()
    print a.x


print a.x
f()
print a.x

1
2
2

在这里,你基本上执行了a=a+1,但是以一种更复杂的方式。这是因为对a的调用被解析为全局变量(并且可以正常工作),而你没有在f()内进行任何赋值。方法add_one在现有对象上被调用——它不关心调用者是否是全局还是局部。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接