在Python中,为什么list[]自动是全局的?

12 投票
5 回答
16023 浏览
提问于 2025-04-16 19:28

这真是个奇怪的情况。

试试这个:

rep_i=0
print "rep_i is" , rep_i
def test():
  global rep_i #without Global this gives error but list , dict , and others don't
  if rep_i==0:
    print "Testing Integer %s" % rep_i
    rep_i=1
  return "Done"

rep_lst=[1,2,3]
 

def test2():
  if rep_lst[0]==1:
    print "Testing List %s" % rep_lst
  return "Done"


if __name__=="__main__":
  test()
  test2()

为什么列表不需要声明为全局变量?它们是不是自动就变成全局的了?

我觉得这真的很奇怪,我大多数时候都在用列表,但我根本不需要用到全局变量来把它们当作全局使用……

5 个回答

5

在Python中,有一个错误叫做UnboundLocalError,这个错误常常让新手感到困惑。让人困惑的是:未来的赋值确实会改变变量的查找方式。

当解释器第一次看到一个变量名时,它会查看当前代码块的结尾。如果在这个代码块内没有对这个变量的赋值,解释器就会把它当作全局变量。如果有赋值,那它就被视为局部变量,这样在赋值之前引用它就会产生UnboundLocalError错误。这就是你遇到的错误。因此,你需要声明global rep_i。如果你没有对rep_i进行赋值,就不需要这一行。

另外,这个问题和变量的类型没有关系。而且,给列表赋值或添加项目(你可能想做这个,但没有做到)并不是对列表本身的赋值,这实际上是在调用列表对象的方法,这和赋值是不同的:赋值会创建一个新对象(可能是在一个已经存在的名称下),而操作列表只是改变了一个已有的列表。

你可以尝试一下:

In [1]: # It won't work with small integers, as they are cached singletons in CPython

In [2]: a = 123123

In [3]: id (a)
Out[3]: 9116848

In [4]: a = 123123

In [5]: id(a)
Out[5]: 9116740

In [6]: # See, it changed

In [7]: # Now with lists

In [8]: l = [1,2,3]

In [9]: id(l)
Out[9]: 19885792

In [10]: l[1] = 2

In [11]: id(l)
Out[11]: 19885792

In [12]: # See, it is the same

In [13]: # But if i reassign the list, even to the same value

In [14]: l = [2,2,3]

In [15]: id(l)
Out[15]: 19884272
5

你只有在给全局变量赋值的时候才需要用到 global。如果不使用 global,那么赋值就会在本地创建一个新的变量。

对于列表来说,global 并没有什么特别的作用——它只是影响变量的作用范围和名称解析。

17

这并不是自动变成全局的。

不过,rep_i=1rep_lst[0]=1 之间是有区别的——前者是重新绑定了名字 rep_i,所以需要用到 global 来防止创建一个同名的局部变量。而后者只是修改了一个已经存在的全局对象,这个对象通过正常的名字查找就能找到(修改列表中的一个元素就像是在调用列表的一个成员函数,这并不是重新绑定名字)。

想测试一下的话,可以在 test2 里尝试赋值 rep_lst=[](也就是把它设置成一个新的列表)。除非你声明 rep_lstglobal,否则在 test2 外面是看不到效果的,因为这时会创建一个同名的局部变量,遮住了全局变量。

撰写回答