Python 全球词典不';不需要关键字全局来修改它们?

Python 全球词典不';不需要关键字全局来修改它们?,python,dictionary,scope,global-variables,global,Python,Dictionary,Scope,Global Variables,Global,我想知道为什么我可以在没有global关键字的情况下更改全局字典?为什么对其他类型是强制性的?这背后有什么逻辑吗 例如,代码: #!/usr/bin/env python3 stringvar = "mod" dictvar = {'key1': 1, 'key2': 2} def foo(): dictvar['key1'] += 1 def bar(): stringvar = "bar" print(stringvar) print(d

我想知道为什么我可以在没有
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)
给出了以下结果:

me@pc:~/$ ./globalDict.py 
{'key2': 2, 'key1': 1}
{'key2': 2, 'key1': 2}  # Dictionary value has been changed
mod
bar
mod
我希望:

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

您可以修改任何可变对象,而无需使用
global
关键字

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

但对于可变对象,您并没有重新分配任何内容,您只是就地修改它们,因此Python只是从全局范围加载它们并修改它们

比如说:

如果没有全局变量,就不可能分配给全局变量

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  

原因是这条线

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

但是,

dictvar['key1'] += 1
这是完全明确的。它只能引用全局变量
dictvar
,因为
dictvar
必须已经存在,语句才不会抛出错误

这并不特定于词典-列表也是如此:

listvar = ["hello", "world"]

def listfoo():
    listvar[0] = "goodbye"
或其他类型的对象:

class MyClass:
    foo = 1
myclassvar = MyClass()

def myclassfoo():
    myclassvar.foo = 2

每当我读到一个.

时都是这样,所以我知道字典在没有
全局
的情况下是如何工作的,但我仍然无法理解为什么Python根据变量类型有不同的作用域方法?您还没有理解Python中可变对象和不可变对象之间的区别。如果您阅读了(至少是第3.1小节,不要因为您认为自己已经知道它而跳过其中的一部分),那么它应该变得清晰起来。在这个问题中,Python 3没有任何特定的内容。我知道我可以做到这一点(以及它背后的机制)。让我烦恼的是,为什么Python会对
global
语句进行例外处理?@Jovik:没有例外。您混淆了变量赋值和值操作。您不能执行
var='string'
var.insert(0,'othertext')
,因为字符串是不可变的,您只能替换变量指向的值。但是你可以改变一个变量。您可以执行
var1={}
var2=var1
var2.update({'other':'dict'})
,您将看到
var1
反映了相同的更改。您更改了一个可变值,而不是指向它的变量。
stringvar=“bar”
只有在考虑Python以外的语言时才是不明确的。有人能从这个答案中得到的唯一勉强是积极的信息是最底层的链接。@mmgp:我想你误解了我。我并不是说这种行为是模棱两可或未定义的。OP问Python为什么会这样做,我解释了为什么它没有选择——因为它不知道什么时候有行
stringvar=“bar”
是指全局变量还是创建局部变量。因此,它默认创建一个局部变量。因此,如果有一个局部字典也称为
dictvar
,它会在全局字典之前首先被调用吗?@Jin是的,没错!
class MyClass:
    foo = 1
myclassvar = MyClass()

def myclassfoo():
    myclassvar.foo = 2