导入模块

时间:2017-07-27 17:53:14

标签: python python-3.x function

我有以下代码: 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

1 个答案:

答案 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?