函数何时(如果有的话)识别已在main
函数中初始化的变量?
例如:当我编写以下 Python 代码时:
def plus():
variable += 1
if __name__ == '__main__':
variable = 1
plus()
我收到以下错误:UnboundLocalError: local variable 'variable' referenced before assignment
但是,当我做类似的事情时,但有一个dictionary
:
def plus():
dic[1] += 1
if __name__ == '__main__':
dic = {}
dic[1] = 1
plus()
print dic[1]
输出为:2
这两种情况有什么区别?
+=
运算符在与简单变量一起使用时被视为赋值。因此,Python在解析函数体时会在<function_object>.func_code.co_varnames
中添加variable
,因此在运行时,Python永远不会在任何其他范围内查找该变量,除非您在函数顶部有global
或nonlocal
声明(仅限Python 3)。请注意,在将变量与 +=
一起使用之前是否使用 variable
并不重要(请参阅上一个示例),变量现在在函数体中的任何地方都是局部的。
>>> def plus():
... var += 1
...
>>> dis.dis(plus)
2 0 LOAD_FAST 0 (var)
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_FAST 0 (var)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
另一方面,dic[1]
变量查找后跟一个BINARY_SUBSCR
(LOAD_ATTR
也是如此;你可以做x.extend([100])
但不能x+=[100]
;其中x
是一个列表),因为之后没有与dic
相关的赋值语句,Python将其视为全局变量(LOAD_GLOBAL
)或自由变量(LOAD_DEREF
),并从那里获取其值。
>>> def plus():
var[0] += 1
...
>>> dis.dis(plus)
2 0 LOAD_GLOBAL 0 (var)
3 LOAD_CONST 1 (0)
6 DUP_TOPX 2
9 BINARY_SUBSCR
10 LOAD_CONST 2 (1)
13 INPLACE_ADD
14 ROT_THREE
15 STORE_SUBSCR
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
>>> def plus_with_twist():
var[0] += 1 # this will fail due to the next line
var += 1 # Now `var` is a local variable everywhere in the function body
>>> dis.dis(plus_with_twist)
2 0 LOAD_FAST 0 (var)
3 LOAD_CONST 1 (0)
6 DUP_TOPX 2
9 BINARY_SUBSCR
10 LOAD_CONST 2 (1)
13 INPLACE_ADD
14 ROT_THREE
15 STORE_SUBSCR
3 16 LOAD_FAST 0 (var)
19 LOAD_CONST 2 (1)
22 INPLACE_ADD
23 STORE_FAST 0 (var)
26 LOAD_CONST 0 (None)
29 RETURN_VALUE