python中的局部/全局变量混淆

mav*_*vix 3 python

可能重复:
在python中赋值错误之前引用

我在python中遇到一个奇怪的错误.以下ipython日志对其进行了总结:

In [10]: def confused(stuff):
   ....:     print huh
   ....:     return stuff
   ....: 

In [11]: confused(87)
0
Out[11]: 87

In [12]: def confused(stuff):
   ....:     print huh
   ....:     huh += 1
   ....:     return stuff
   ....: 

In [13]: confused(9)
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
/home/max/verk/btr-email/build/x86_64/bin/ipython in <module>()
----> 1 confused(9)

/home/max/verk/btr-email/build/x86_64/bin/ipython in confused(stuff)
      1 def confused(stuff):
----> 2     print huh
      3     huh += 1
      4     return stuff

UnboundLocalError: local variable 'huh' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

有效的函数和抛出错误的函数之间的唯一区别是+ = 1行,即使这样,它也会在以前工作的行上抛出错误!如果我在方法的第二个版本中global huh引用之前放置它也不会引发错误huh.

为什么添加一行我在变量中添加一行会突然从全局变量变为局部变量?

mgi*_*son 7

在您的脚本中,huh引用全局变量.您无法在不明确告知python的情况下更改函数中对全局变量的引用:

def confused(stuff):
    global huh
    print huh
    huh += 1
    return stuff
Run Code Online (Sandbox Code Playgroud)

对于不可变对象,如整数,字符串,浮点数等,这意味着您无法在不声明对象的情况下对对象进行任何更改global.对于可变对象,您可以更改对象项或属性,但仍然无法更改对象的引用.


这都是范围问题.由于huh不在本地范围内confused,python在全局范围内找到它.由于它是在全局范围内找到的,因此除非您明确说明您想要(使用我上面所做的),否则您无法分配global.但是,如果它是一个list,一旦列表中找到,您可以访问所有这些列表的方法(包括__setitem__,append等等)


至于错误的位置,这可以通过一点dis组装来清除:

>>> def confused(stuff):
...    print huh
... 

>>> import dis
>>> dis.dis(confused)
  2           0 LOAD_GLOBAL              0 (huh)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE

>>> def confused2(stuff):
...    print huh
...    huh += 1
... 

>>> dis.dis(confused2)
  2           0 LOAD_FAST                1 (huh)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       

  3           5 LOAD_FAST                1 (huh)
              8 LOAD_CONST               1 (1)
             11 INPLACE_ADD         
             12 STORE_FAST               1 (huh)
             15 LOAD_CONST               0 (None)
             18 RETURN_VALUE   
Run Code Online (Sandbox Code Playgroud)

你可以看到confused2,python已经LOAD_FAST在函数的第一行尝试(意思是寻找局部变量).但是,没有局部变量huh因此存在异常.

  • @mavix除了mgilson所说的,这个用于确定本地和什么是全局的规则消除了声明局部变量的需要(到目前为止最常见的类型,所以我们不希望它是冗长的),同时允许访问读取-only全局(包括类,函数,导入等,因为它们都共享相同的命名空间),并且仅仅通过查看函数的代码仍然明确区分全局和本地. (3认同)