python - 在 Python 2/3 中访问函数内部的全局变量时出现异常

标签 python scope

<分区>

如果不使用global 关键字,则无法在函数内访问全局变量; (很好)但我没想到会出现以下情况:

案例一:

a = 1

def f():
  a += 1
  print(a)

>>> f()
...
UnboundLocalError: local variable 'a' referenced before assignment

我推测的原因:函数在其本地范围内找不到变量 a

案例二:

a = 1

def f():
  print(a)

>>> f()
1

但是现在,该函数在其本地范围内找到变量 a。 矛盾,我在前面的案例中推测的原因。

为什么会这样?

最佳答案

这是因为对于你的第二个例子,编译器试图用一些魔法来帮助你。在这种情况下

def f():
  print(a)

这是它缩减为的字节码:

dis.dis(f)
  2           0 LOAD_GLOBAL              0 (print) 
              3 LOAD_GLOBAL              1 (a) #aha!
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
              9 POP_TOP              
             10 LOAD_CONST               0 (None) 
             13 RETURN_VALUE

您可以看到,由于您从未在 f 范围内分配给 a,因此编译器知道您必须指的是全局.

当您开始分配a时,现在编译器不会尝试帮助您。除非您明确告诉它 a 是全局的,否则它会将其视为本地的。

def g():
    x += 1

dis.dis(g)
  2           0 LOAD_FAST                0 (x) #note no assumption that it is global
              3 LOAD_CONST               1 (1) 
              6 INPLACE_ADD          
              7 STORE_FAST               0 (x) 
             10 LOAD_CONST               0 (None) 
             13 RETURN_VALUE  

现在你可以问这个问题了,好吧,但是为什么编译器在你的第一个例子中没有帮助你呢?一种解释方式当然是“显式优于隐式”。虽然编译器当然在你的第二个例子中隐含地做了一些事情,所以也许这不是一个令人满意的解释:)。

主要归结为这就是 Python 的工作原理,我想说。如果您分配给一个变量,python 将其视为该范围的局部变量,除非您另有说明。所以你的声明:

Global variables cannot be accessed within a function without using the global keyword

不太正确。您可以从外部作用域访问变量,但您不能在未明确声明的情况下分配给所述变量。


旁注,这是完全合法的:

x = [1]

def f():
    x[0] += 1

f()
#x is now [2]

这可能令人困惑 :-)。这是因为在这种情况下,您没有在 x 持有的引用上分配任何东西; += 运算符实际上调用列表的 __setattr__ 方法来更改属性。在 python 2 中,这个技巧经常被用作没有 nonlocal 关键字的解决方法。

关于python - 在 Python 2/3 中访问函数内部的全局变量时出现异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20456582/

相关文章:

python - 导入错误 : cannot import name DependencyWarning

python - statsmodel 属性错误 : module 'scipy.stats' has no attribute 'chisqprob'

python - "Stackdriver Debugger is not set up for the python runtime on GAE Flex"警告

javascript - JSON 输出在代码中仍未定义,但警报正常,这是范围问题吗?

ruby - block 局部变量的存在只是为了增强可读性吗?

garbage-collection - CDI 应用程序和从属范围会合谋影响垃圾收集吗?

python - 根据特定列中的值将函数应用于 Pandas 中的数据框行

python - 在 Python 中迭代时如何在字典中选择键

angularjs - AngularJS 中的范围未更新

javascript - 跨浏览器 Javascript 函数作用域问题