我有以下代码:
one.py
import two as t
t.test1()
t.test2()
two.py
class test_class():
def __init__(self,arg):
print("created obj name is {}".format(arg))
self.name = arg
non_global ="initial global"
obj = test_class("test name")
def test1():
print("\t in test 1")
print (obj.name)
global non_global # wont work without global keyword, value still refers to "initial value"
print(non_global) # initial value
obj.name = "changed"
#non_global = "changed global"
def test2():
print("\tin test 2")
print(obj.name)
print(non_global)
结果是:
created obj name is test name
in test 1
test name
initial global
in test 2
changed
changed global
如果我将test1()
更改为:
def test1():
print("\t in test 1")
print (obj.name)
#global non_global # wont work without global keyword, value still refers to "initial value"
print(non_global) # initial value
obj.name = "changed"
non_global = "changed global"
我在打印行上收到错误UnboundLocalError: local variable 'non_global' referenced before assignment
。
如果我评论non_global = "changed global"
,则错误就会消失。
我的问题是:
为什么non_global
而不是obj
发生这种情况?我在python 3.5
答案 0 :(得分:4)
差异基本上是non_global
是变量赋值,obj.name
是属性赋值。
函数中的变量赋值使该变量成为局部变量,并且由于Python不会在本地范围之外的任何地方查找它,因此print(non_global)
失败,因为它尚未定义在那个范围内。这适用于global
语句,因为通过使用global
,您告诉Python不要将其视为局部变量,因此可以从全局范围获取其值。
在解析函数体时会决定变量是否转到本地,因此在实际声明之前尝试使用它时,您将在运行时收到错误。
另一方面, obj.name
基本上使用简单LEGB lookup搜索obj
,然后使用指定值设置name
属性。
同样,您也可以在不使用global
的情况下更新函数体中的全局可变数据结构(list,dict等)。
除了=
之外,*=
,+=
等扩充分配也会将变量设为局部变量。
a = []
def func1():
a += ['foo']
def func2():
a.extend(['bar'])
def func3():
a[0] += 'spam'
func1() # Fails with UnboundLocalError: local variable 'a' referenced before assignment
func2() # works fine
func3() # Also works fine because a[0] is not a variable.
# We are telling Python to look for `a` and fetch its 0th item
# and concatenate 'spam' to it.
print(a) # prints ['barspam']
字节码反汇编也可以帮助您指出差异:
>>> import dis
>>> dis.dis(func1)
45 0 LOAD_FAST 0 (a)
3 LOAD_CONST 1 ('foo') # Load a local variable name foo
6 BUILD_LIST 1
9 INPLACE_ADD
10 STORE_FAST 0 (a) # Store local variable named foo
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>> dis.dis(func2)
48 0 LOAD_GLOBAL 0 (a) # Load from global scope
3 LOAD_ATTR 1 (extend)
6 LOAD_CONST 1 ('bar')
9 BUILD_LIST 1
12 CALL_FUNCTION 1
15 POP_TOP
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
>>> dis.dis(func3)
51 0 LOAD_GLOBAL 0 (a) # Load from global scope
3 LOAD_CONST 1 (0)
6 DUP_TOPX 2
9 BINARY_SUBSCR
10 LOAD_CONST 2 ('spam')
13 INPLACE_ADD
14 ROT_THREE
15 STORE_SUBSCR
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
# Names of local variables or arguments of each function obtained through its code object
>>> func1.__code__.co_varnames
('a',)
>>> func2.__code__.co_varnames
()
>>> func3.__code__.co_varnames
()
相关:Why am I getting an UnboundLocalError when the variable has a value?