Python recognize/not 什么时候识别 main 中的变量?
When does Python recognize/not recognize variables from main?
函数何时(如果有的话)识别已在 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
这两种情况有什么区别?
+=
运算符在与 simple 变量一起使用时被视为赋值。因此,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
(same thing for LOAD_ATTR
as well; you can do x.extend([100])
but not x+=[100]
; where x
is a list) and as there are no assignment statements related to dic
after that Python considers it as a either a global variable(LOAD_GLOBAL
) or a free variable(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
函数何时(如果有的话)识别已在 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
这两种情况有什么区别?
+=
运算符在与 simple 变量一起使用时被视为赋值。因此,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
(same thing for LOAD_ATTR
as well; you can do x.extend([100])
but not x+=[100]
; where x
is a list) and as there are no assignment statements related to dic
after that Python considers it as a either a global variable(LOAD_GLOBAL
) or a free variable(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