全局词典不需要关键字全局来修改它们吗?

Jov*_*vik 32 python dictionary scope global global-variables

可能重复:
为什么在这种情况下不需要全局关键字?

我想知道为什么我可以在没有global关键字的情 为什么它对其他类型是强制性的?这背后有什么逻辑吗?

例如代码:

#!/usr/bin/env python3

stringvar = "mod"
dictvar = {'key1': 1,
           'key2': 2}

def foo():
    dictvar['key1'] += 1

def bar():
    stringvar = "bar"
    print(stringvar)

print(dictvar)
foo()
print(dictvar)

print(stringvar)
bar()
print(stringvar)
Run Code Online (Sandbox Code Playgroud)

给出以下结果:

me@pc:~/$ ./globalDict.py 
{'key2': 2, 'key1': 1}
{'key2': 2, 'key1': 2}  # Dictionary value has been changed
mod
bar
mod
Run Code Online (Sandbox Code Playgroud)

我期待的地方:

me@pc:~/$ ./globalDict.py 
{'key2': 2, 'key1': 1}
{'key2': 2, 'key1': 1}  # I didn't use global, so dictionary remains the same
mod
bar
mod
Run Code Online (Sandbox Code Playgroud)

Dav*_*son 41

原因是这条线

stringvar = "bar"
Run Code Online (Sandbox Code Playgroud)

是不明确的,它可能是指一个全局变量,或者它可能是创建一个名为的新局部变量stringvar.在这种情况下,Python默认假设它是一个局部变量,除非global已经使用了该关键字.

但是,行

dictvar['key1'] += 1
Run Code Online (Sandbox Code Playgroud)

完全是毫不含糊的.它只能引用全局变量dictvar,因为dictvar语句必须已存在才能抛出错误.

这不是字典特有的 - 列表也是如此:

listvar = ["hello", "world"]

def listfoo():
    listvar[0] = "goodbye"
Run Code Online (Sandbox Code Playgroud)

或其他类型的物品:

class MyClass:
    foo = 1
myclassvar = MyClass()

def myclassfoo():
    myclassvar.foo = 2
Run Code Online (Sandbox Code Playgroud)

每当使用变异操作而不是重新绑定操作时都是如此.

  • @mmgp:我想你误解了我.我不是说这种行为含糊不清或不明确.OP问的是为什么Python会像它一样行事,而我正在解释为什么它没有选择 - 因为它无法知道你什么时候有`stringvar ="bar"`你是否想要引用全局变量或创建局部变量.因此,它默认为创建局部变量. (7认同)

Ash*_*ary 7

您可以不使用global关键字修改任何可变对象.

这在Python中是可能的,因为global当您想要将新对象重新分配给已在全局范围中使用的变量名称或定义新的全局变量时使用.

但是在可变对象的情况下,你不会重新分配任何东西,你只需要就地修改它们,因此Python只是从全局范围加载它们并修改它们.

正如文档所说:

没有全局变量就不可能分配给全局变量.

In [101]: dic = {}

In [102]: lis = []

In [103]: def func():
    dic['a'] = 'foo'
    lis.append('foo') # but  fails for lis += ['something']
   .....:     

In [104]: func()

In [105]: dic, lis
Out[105]: ({'a': 'foo'}, ['foo'])
Run Code Online (Sandbox Code Playgroud)

dis.dis:

In [121]: dis.dis(func)
  2           0 LOAD_CONST               1 ('foo')
              3 LOAD_GLOBAL              0 (dic)     # the global object dic is loaded
              6 LOAD_CONST               2 ('a')
              9 STORE_SUBSCR                         # modify the same object

  3          10 LOAD_GLOBAL              1 (lis)    # the global object lis is loaded
             13 LOAD_ATTR                2 (append)
             16 LOAD_CONST               1 ('foo')
             19 CALL_FUNCTION            1
             22 POP_TOP             
             23 LOAD_CONST               0 (None)
             26 RETURN_VALUE  
Run Code Online (Sandbox Code Playgroud)