web-dev-qa-db-fra.com

Les dictionnaires globaux n'ont pas besoin de mot-clé global pour les modifier?

Duplicata possible:
Pourquoi le mot-clé global n'est-il pas requis dans ce cas?

Je me demande pourquoi je peux changer le dictionnaire global sans global mot-clé? Pourquoi est-il obligatoire pour les autres types? Y a-t-il une logique derrière tout cela?

Par exemple. code:

#!/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)

Donne les résultats suivants:

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

où je m'attendrais:

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
31
Jovik

La raison en est que la ligne

stringvar = "bar"

est ambigu, il pourrait faire référence à une variable globale, ou il pourrait être en train de créer une nouvelle variable locale appelée stringvar. Dans ce cas, Python par défaut suppose qu'il s'agit d'une variable locale sauf si le mot clé global a déjà été utilisé.

Cependant, la ligne

dictvar['key1'] += 1

Est entièrement sans ambiguïté. Il peut se référer uniquement à la variable globale dictvar, car dictvar doit déjà exister pour que l'instruction ne génère pas d'erreur.

Ce n'est pas spécifique aux dictionnaires - il en va de même pour les listes:

listvar = ["hello", "world"]

def listfoo():
    listvar[0] = "goodbye"

ou d'autres types d'objets:

class MyClass:
    foo = 1
myclassvar = MyClass()

def myclassfoo():
    myclassvar.foo = 2

C'est vrai chaque fois qu'une ne opération de mutation est utilisée plutôt qu'une opération de reliure .

41
David Robinson

Vous pouvez modifier n'importe quel objet modifiable sans utiliser le mot clé global.

Cela est possible dans Python car global est utilisé lorsque vous souhaitez réaffecter de nouveaux objets à des noms de variable déjà utilisés dans la portée globale ou pour définir de nouvelles variables globales.

Mais dans le cas d'objets mutables, vous ne réattribuez rien, vous les modifiez simplement sur place, donc Python les charge simplement à partir de la portée globale et les modifie.

Comme docs dites:

Il serait impossible d'affecter à une variable globale sans global.

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'])

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  
7
Ashwini Chaudhary