86 votes

Comment puis-je accéder à une variable globale dans une classe en Python ?

J'ai ça :

g_c = 0

class TestClass():
    global g_c
    def run(self):
        for i in range(10):
            g_c = 1
            print(g_c)

t = TestClass()
t.run()

print(g_c)

comment puis-je réellement modifier ma variable globale g_c ?

133voto

unwind Points 181987

En le déclarant global à l'intérieur de la fonction qui y accède :

g_c = 0

class TestClass():
    def run(self):
        global g_c
        for i in range(10):
            g_c = 1
            print(g_c)

En Documentation Python dit ceci, à propos de la global déclaration :

La déclaration globale est une déclaration qui s'applique à l'ensemble du bloc de code en cours.

23voto

Martijn Pieters Points 271458

Vous devez déplacer le global dans votre fonction :

class TestClass():
    def run(self):
        global g_c
        for i in range(10):
            g_c = 1
            print(g_c)

Cette instruction indique au compilateur Python que toute affectation (et tout autres actions contraignantes ) à ce nom sont de modifier la valeur dans l'espace de noms global ; par défaut, tout nom qui est assigné à un endroit quelconque d'une fonction, est placé dans l'espace de noms local. L'instruction ne s'applique qu'à la portée actuelle.

Puisque vous n'assignez jamais à g_c en el corps de classe si vous mettez la déclaration à cet endroit, cela n'a aucun effet. Le site global ne s'applique qu'à l'étendue dans laquelle elle est utilisée, jamais aux étendues imbriquées. Voir l'article global documentation des relevés qui s'ouvre par :

La déclaration globale est une déclaration qui s'applique à l'ensemble du bloc de code en cours.

Les fonctions et classes imbriquées ne font pas partie du bloc de code actuel.

Je vais insérer ici l'avertissement obligatoire contre l'utilisation des globaux pour partager les changements d'état : ne le faites pas, cela rend plus difficile le raisonnement sur l'état de votre code, plus difficile les tests, plus difficile la refactorisation, etc. Si vous debe partagent un état singleton changeant (une seule valeur dans l'ensemble du programme), alors utilisez au moins un fichier de type attribut de classe :

class TestClass():
    g_c = 0

    def run(self):
        for i in range(10):
            TestClass.g_c = 1
            print(TestClass.g_c)  # or print(self.g_c)

t = TestClass()
t.run()

print(TestClass.g_c)

Notez que nous pouvons toujours accéder à la même valeur depuis l'extérieur, en utilisant l'espace de nom de l'utilisateur. TestClass espace de noms.

9voto

Patrick Kilecdi Points 91

Je comprends que l'utilisation d'une variable globale est parfois la chose la plus pratique à faire, surtout dans les cas où l'utilisation d'une classe rend la chose la plus simple beaucoup plus difficile (par exemple, multiprocessing ). J'ai rencontré le même problème avec la déclaration des variables globales et je l'ai résolu par quelques expériences.

La raison pour laquelle g_c n'a pas été modifié par le run au sein de votre classe est que la référence au nom global dans g_c n'a pas été établi précisément dans le cadre de la fonction. La façon dont Python gère les déclarations globales est en fait assez délicate. La commande global g_c a deux effets :

  1. Conditions préalables à l'entrée de la clé "g_c" dans le dictionnaire accessible par la fonction intégrée, globals() . Cependant, la clé n'apparaîtra dans le dictionnaire qu'après qu'une valeur lui ait été attribuée.

  2. (Potentiellement) modifie la façon dont Python recherche la variable g_c dans le cadre de la méthode actuelle.

La compréhension complète de (2) est particulièrement complexe. Tout d'abord, il ne modifie que potentiellement, car si aucune affectation au nom g_c se produit dans la méthode, Python la recherche par défaut parmi les éléments suivants globals() . Il s'agit en fait d'une chose assez courante, comme dans le cas de la référence à l'intérieur d'une méthode de modules qui sont importés tout au début du code.

Cependant, si une commande d'affectation se produit partout au sein de la méthode, Python recherche par défaut le nom g_c dans les variables locales. Cela est vrai même lorsqu'une référence se produit avant une affectation réelle, ce qui entraînera l'erreur classique :

UnboundLocalError: local variable 'g_c' referenced before assignment

Maintenant, si la déclaration global g_c se produit partout dans la méthode, même après toute référence ou affectation, Python recherche par défaut le nom g_c dans les variables globales. Toutefois, si vous vous sentez d'humeur expérimentale et que vous placez la déclaration après une référence, vous serez récompensé par un avertissement :

SyntaxWarning: name 'g_c' is used prior to global declaration

Si vous y réfléchissez, la façon dont la déclaration globale fonctionne en Python est clairement intégrée et cohérente avec le fonctionnement normal de Python. C'est juste quand vous voulez vraiment qu'une variable globale fonctionne, que la norme devient gênante.

Voici un code qui résume ce que je viens de dire (avec quelques observations supplémentaires) :

g_c = 0
print ("Initial value of g_c: " + str(g_c))
print("Variable defined outside of method automatically global? "
      + str("g_c" in globals()))

class TestClass():
    def direct_print(self):
        print("Directly printing g_c without declaration or modification: "
              + str(g_c))
        #Without any local reference to the name
        #Python defaults to search for the variable in globals()
        #This of course happens for all the module names you import

    def mod_without_dec(self):
        g_c = 1
        #A local assignment without declaring reference to global variable
        #makes Python default to access local name
        print ("After mod_without_dec, local g_c=" + str(g_c))
        print ("After mod_without_dec, global g_c=" + str(globals()["g_c"]))

    def mod_with_late_dec(self):
        g_c = 2
        #Even with a late declaration, the global variable is accessed
        #However, a syntax warning will be issued
        global g_c
        print ("After mod_with_late_dec, local g_c=" + str(g_c))
        print ("After mod_with_late_dec, global g_c=" + str(globals()["g_c"]))

    def mod_without_dec_error(self):
        try:
            print("This is g_c" + str(g_c))
        except:
            print("Error occured while accessing g_c")
            #If you try to access g_c without declaring it global
            #but within the method you also alter it at some point
            #then Python will not search for the name in globals()
            #!!!!!Even if the assignment command occurs later!!!!!
        g_c = 3

    def sound_practice(self):
        global g_c
        #With correct declaration within the method
        #The local name g_c becomes an alias for globals()["g_c"]
        g_c = 4
        print("In sound_practice, the name g_c points to: " + str(g_c))

t = TestClass()
t.direct_print()
t.mod_without_dec()
t.mod_with_late_dec()
t.mod_without_dec_error()
t.sound_practice()

5voto

Jim Points 51
class flag:
    ## Store pseudo-global variables here

    keys=False

    sword=True

    torch=False

## test the flag class

print('______________________')

print(flag.keys)
print(flag.sword)
print (flag.torch)

## now change the variables

flag.keys=True
flag.sword= not flag.sword
flag.torch=True

print('______________________')

print(flag.keys)
print(flag.sword)
print (flag.torch)

2voto

Manohar Royal Points 29

Il est très simple de rendre une variable globale dans une classe :

a = 0

class b():
    global a
    a = 10

>>> a
10

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X