Utilisation du mot-clé «global» en Python

285

Ce que je comprends de la lecture de la documentation, c'est que Python a un espace de noms séparé pour les fonctions, et si je veux utiliser une variable globale dans cette fonction, je dois l'utiliser global.

J'utilise Python 2.7 et j'ai essayé ce petit test

>>> sub = ['0', '0', '0', '0']
>>> def getJoin():
...     return '.'.join(sub)
...
>>> getJoin()
'0.0.0.0'

Il semble que les choses fonctionnent bien même sans global. J'ai pu accéder à la variable globale sans aucun problème.

Suis-je en train de manquer quelque chose? En outre, ce qui suit provient de la documentation Python:

Les noms répertoriés dans une instruction globale ne doivent pas être définis en tant que paramètres formels ou dans une cible de contrôle de boucle for, une définition de classe, une définition de fonction ou une instruction d'importation.

Bien que les paramètres formels et la définition de classe aient un sens pour moi, je ne suis pas en mesure de comprendre la restriction de la définition de la fonction et de la cible du contrôle de boucle.

nik
la source
1
Je pense que vous êtes confondu avec php qui nécessite l'utilisation du mot clé global - les documents python le confirment - fondamentalement s'il n'est pas défini dans le contexte local, il est traité comme global
tobyodavies
11
Soyez prudent avec votre formulation: Python n'a pas d'espace de noms séparé pour les fonctions (cela signifierait que vous pourriez en avoir def foo(): ...et foo = ...en même temps). Il crée une nouvelle portée pour chaque appel de fonction. (Mais en quoi est-ce différent de tous les autres langages de haut niveau à distance dans le monde?)

Réponses:

366

Le mot global- clé n'est utile que pour modifier ou créer des variables globales dans un contexte local, bien que la création de variables globales soit rarement considérée comme une bonne solution.

def bob():
    me = "locally defined"    # Defined only in local context
    print(me)

bob()
print(me)     # Asking for a global variable

Ce qui précède vous donnera:

locally defined
Traceback (most recent call last):
  File "file.py", line 9, in <module>
    print(me)
NameError: name 'me' is not defined

Alors que si vous utilisez l' globalinstruction, la variable deviendra disponible "en dehors" de la portée de la fonction, devenant ainsi une variable globale.

def bob():
    global me
    me = "locally defined"   # Defined locally but declared as global
    print(me)

bob()
print(me)     # Asking for a global variable

Ainsi, le code ci-dessus vous donnera:

locally defined
locally defined

De plus, en raison de la nature de python, vous pouvez également utiliser globalpour déclarer des fonctions, des classes ou d'autres objets dans un contexte local. Bien que je le déconseille, car cela provoque des cauchemars si quelque chose se passe mal ou doit être débogué.

unode
la source
59
«global» dans ce contexte semble être différent des autres langues considérées comme «global». En Python, une référence "globale" est toujours dans les limites du module et devrait être référencée de l'extérieur de ce module en tant que "module.global_var" plutôt que simplement "global_var" comme on pourrait s'y attendre.
jus du
17
@juice - En Python, l'absolu n'est pas globalsdéfini automatiquement dans tous les espaces de noms (heureusement). Comme vous l'avez correctement souligné, un global est lié à un espace de noms dans un module, mais il peut être importé dans un autre module sous la forme from module import variableou import module.variable. Dans le premier cas, l'importation rendrait la variable accessible comme variablesans nécessiter de référence comme module.. S'il est considéré comme global dans la portée du module, cela dépendra de l'endroit où il est importé. Voir aussi nonlocalcomme un nouveau mot-clé lié à la portée en python 3.
unode
3
Pourriez-vous expliquer pourquoi les variables globales ne sont pas une bonne solution? J'entends souvent cela, mais dans mon projet actuel, ils semblent faire exactement ce dont j'ai besoin. Y a-t-il quelque chose de plus sinistre auquel je n'ai pas pensé?
Robin Newhouse
5
@RobinNewhouse Il y a quelques questions sur SO couvrant déjà ce sujet et d'autres articles non SO .
onode
213

Bien que vous puissiez accéder aux variables globales sans le globalmot - clé, si vous souhaitez les modifier, vous devez utiliser le globalmot - clé. Par exemple:

foo = 1
def test():
    foo = 2 # new local foo

def blub():
    global foo
    foo = 3 # changes the value of the global foo

Dans votre cas, vous accédez simplement à la liste sub.

Ivo Wetzel
la source
3
Avec une mise en garde: foo = 3sans travaux globaux, mais foo est à nouveau défini localement dans la blubportée de la fonction et ne modifie pas la variable foo d'origine. C'était assez déroutant pour moi.
chhantyal
1
@chhantyal si par travaux, vous voulez dire qu'il ne génère pas d'erreur, vous avez raison, mais dans le contexte d'Ivo Wetzel, il ne fonctionnerait pas comme prévu. Il existe des utilisations pour un tel comportement, mais ce n'est souvent pas ce que le programmeur veut.
démocidiste le
77

C'est la différence entre accéder au nom et le lier dans une portée.

Si vous recherchez simplement une variable pour lire sa valeur, vous avez accès à la portée globale et locale.

Cependant, si vous attribuez à une variable dont le nom n'est pas dans la portée locale, vous liez ce nom dans cette portée (et si ce nom existe également en tant que global, vous le masquerez).

Si vous voulez pouvoir attribuer au nom global, vous devez dire à l'analyseur d'utiliser le nom global plutôt que de lier un nouveau nom local - ce que fait le mot-clé 'global'.

La liaison n'importe où dans un bloc provoque la liaison du nom partout dans ce bloc, ce qui peut entraîner des conséquences assez étranges (par exemple UnboundLocalError apparaissant soudainement dans du code fonctionnant précédemment).

>>> a = 1
>>> def p():
    print(a) # accessing global scope, no binding going on
>>> def q():
    a = 3 # binding a name in local scope - hiding global
    print(a)
>>> def r():
    print(a) # fail - a is bound to local scope, but not assigned yet
    a = 4
>>> p()
1
>>> q()
3
>>> r()
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    r()
  File "<pyshell#32>", line 2, in r
    print(a) # fail - a is bound to local scope, but not assigned yet
UnboundLocalError: local variable 'a' referenced before assignment
>>> 
pycruft
la source
très contre-intuitif, difficile de croire qu'il s'agit d'un code python valide
PlsWork
52

Les autres réponses répondent à votre question. Une autre chose importante à savoir sur les noms en Python est qu'ils sont locaux ou globaux selon la portée.

Considérez ceci, par exemple:

value = 42

def doit():
    print value
    value = 0

doit()
print value

Vous pouvez probablement deviner que l' value = 0instruction sera affectée à une variable locale et n'affectera pas la valeur de la même variable déclarée en dehors de la doit()fonction. Vous pourriez être plus surpris de découvrir que le code ci-dessus ne fonctionnera pas. L'instruction print valueà l'intérieur de la fonction produit unUnboundLocalError.

La raison en est que Python a remarqué que, ailleurs dans la fonction, vous attribuez le nom value, et valuen'est également déclaré nulle part global. Cela en fait une variable locale. Mais lorsque vous essayez de l'imprimer, le nom local n'a pas encore été défini. Dans ce cas, Python ne revient pas à rechercher le nom comme variable globale, comme le font d'autres langages. Essentiellement, vous ne pouvez pas accéder à une variable globale si vous avez défini une variable locale du même nom n'importe où dans la fonction.

gentil
la source
1
Merci de l'avoir signalé. Ainsi, tant que votre portée locale n'assigne pas à un nom qui existe en dehors de celui-ci, les références dans la portée locale utiliseront le nom extérieur. Cependant, si vous affectez un nom à ce nom à n'importe quel endroit de votre fonction, les références dans cette portée locale, même avant l'affectation locale, ne regardent pas à l'extérieur.
Dmitry Minkovsky
1
Exactement, vous l'avez. global(ou nonlocaldans Python 3.x) remplace ce comportement et vous permet de réaffecter le nom externe.
kindall
2
Dans d'autres langues, cela semble être appelé "levage", comme ceci par exemple: github.com/shichuan/javascript-patterns/blob/master/…
Dmitry Minkovsky
Pour ajouter une insulte à une blessure, les variables déclarées avec le nouveau mot clé JavaScript nelet sont pas hissées.
kindall
Est-il plus rapide d'accéder à une variable globale déclarée avec globalou cela n'a pas d'importance?
mato
14

L'accès à un nom et l'attribution d'un nom sont différents. Dans votre cas, vous accédez simplement à un nom.

Si vous attribuez à une variable dans une fonction, cette variable est supposée être locale, sauf si vous la déclarez globale. En l'absence de cela, il est supposé être mondial.

>>> x = 1         # global 
>>> def foo():
        print x       # accessing it, it is global

>>> foo()
1
>>> def foo():   
        x = 2        # local x
        print x 

>>> x            # global x
1
>>> foo()        # prints local x
2
user225312
la source
7
  • Vous pouvez accéder à des mots clés globaux sans mot clé global
  • Pour pouvoir les modifier, vous devez indiquer explicitement que le mot-clé est global. Sinon, le mot clé sera déclaré dans la portée locale.

Exemple:

words = [...] 

def contains (word): 
    global words             # <- not really needed
    return (word in words) 

def add (word): 
    global words             # must specify that we're working with a global keyword
    if word not in words: 
        words += [word]
martynas
la source
2

Toute variable déclarée en dehors d'une fonction est supposée être globale, c'est seulement en les déclarant de l'intérieur des fonctions (sauf les constructeurs) que vous devez spécifier que la variable soit globale.

Jesus Ramos
la source
1

Ceci est bien expliqué dans la FAQ Python

Quelles sont les règles pour les variables locales et globales en Python?

En Python, les variables qui ne sont référencées qu'à l'intérieur d'une fonction sont implicitement globales. Si une variable se voit attribuer une valeur n'importe où dans le corps de la fonction, elle est supposée être locale, sauf si elle est explicitement déclarée comme globale.

Bien qu'un peu surprenant au début, un moment de réflexion explique cela. D'une part, l'exigence globalde variables affectées fournit une barre contre les effets secondaires imprévus. D'un autre côté, si cela globalétait requis pour toutes les références globales, vous utiliseriez globaltout le temps. Vous devez déclarer comme globalchaque référence à une fonction intégrée ou à un composant d'un module importé. Cet encombrement irait à l'encontre de l'utilité de la globaldéclaration pour identifier les effets secondaires.

https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

user7610
la source
0

Cela signifie que vous ne devez pas effectuer les opérations suivantes:

x = 1

def myfunc():
  global x

  # formal parameter
  def localfunction(x):
    return x+1

  # import statement
  import os.path as x

  # for loop control target
  for x in range(10):
    print x

  # class definition
  class x(object):
    def __init__(self):
      pass

  #function definition
  def x():
    print "I'm bad"
ikostia
la source
ikostia énumère toutes les choses que vous ne pouvez pas utiliser 'x' pour avoir utilisé global - docs.python.org/reference/…
pycruft
1
@Unode: Je démontre juste tous les cas que NikhilRathod a donnés dans sa citation.
ikostia
0

Global rend la variable "Global"

def out():
    global x
    x = 1
    print(x)
    return


out()

print (x)

Cela fait que «x» agit comme une variable normale en dehors de la fonction. Si vous supprimiez le global, cela donnerait une erreur car il ne peut pas imprimer une variable à l'intérieur d'une fonction.

def out():
     # Taking out the global will give you an error since the variable x is no longer 'global' or in other words: accessible for other commands
    x = 1
    print(x)
    return


out()

print (x)
Michael
la source