web-dev-qa-db-fra.com

Python: partage de variables globales entre les modules et les classes qu'ils contiennent

Je sais qu'il est possible de partager une variable globale entre les modules en Python. Cependant, je voudrais savoir dans quelle mesure cela est possible et pourquoi. Par exemple,

global_mod.py

x = None

mid_access_mod.py

from global_mod import *

class delta:
    def __init__(self):
        print x

bot_modif_mod.py

import mid_access_mod
import global_mod

class mew:
    def __init__(self):
        global_mod.x = 5

def main():
    m = mew()
    d = mid_access_mod.delta()

Cela affiche None, même si tous les modules partagent la variable globale x. pourquoi est-ce le cas? Il semble que x soit évalué dans mid_access_mod.py avant d'être attribué dans bot_modif_mod.py par mew ().

35
emish

Cela se produit car vous utilisez des valeurs immuables (ints et None), et l'importation de variables revient à passer des choses par valeur, pas à des choses par référence.

Si vous faites de global_mod.x une liste et manipulez son premier élément, cela fonctionnera comme prévu.

Lorsque vous faites from global_mod import x, vous créez un nom x dans votre module avec la même valeur que x a dans global_mod. Pour des choses comme les fonctions et les classes, cela fonctionne comme vous vous en doutez, car les gens (généralement) ne réattribuent pas ces noms plus tard.

Comme le souligne Alex, si vous utilisez import global_mod, puis global_mod.x, vous éviterez le problème. Le nom que vous définissez dans votre module sera global_mod, qui fait toujours référence au module souhaité, puis en utilisant l'accès aux attributs pour obtenir à x vous obtiendrez la dernière valeur de x.

37
Ned Batchelder

from whatever import * est pas un bon idiome à utiliser dans votre code - il est destiné à être utilisé, si jamais, dans une session interactive comme raccourci pour enregistrer une saisie. Il "copie instantanément" tous les noms du module à ce moment-là - si jamais vous liez à nouveau l'un de ces noms, l'instantané sera devenu obsolète et toutes sortes de problèmes s'ensuivront. Et ce n'est que le début du gâchis inextricable auquel vous vous inscrivez en utilisant le misérable from ... import * construire.

Vous voulez mes conseils? Oubliez que vous ayez jamais entendu parler de cette construction existante et que vous ne l'utiliserez plus jamais. Utilisation import global_mod as m et toujours utiliser par la suite qualifié noms tels que m.x - les noms qualifiés sont donc beaucoup plus pratiques et plus puissants en Python, que de simples noms de barres, que ce n'est même pas drôle. (Le as m une partie de l'instruction import est totalement facultative et existe essentiellement à des fins de concision, ou parfois pour contourner certains problèmes avec les conflits de noms; utilisez-le quand et si vous le trouvez pratique, car il n'a pas d'inconvénients, mais ne vous sentez pas obligé ou même exhorté à l'utiliser si vous ne le sentez pas nécessaire).

26
Alex Martelli

Comme l'a mentionné Ned Batchelder, seules les valeurs sont partagées et non l'objet réel. Si vous souhaitez partager un objet par référence, vous recherchez probablement Thread-Local Data.

Par exemple:

import threading

g = threading.local()
g.population = '7 Billion'

Maintenant, chaque fois que vous souhaitez accéder à la variable g.population ou la modifier, vous en obtiendrez une valeur mise à jour, à condition qu'il s'agisse du même thread que celui à partir duquel vous essayez d'y accéder.

En savoir plus dans la documentation Python: https://docs.python.org/3/library/threading.html#thread-local-data

0
Kevin

Pour résoudre ce problème, modifiez simplement from global_mod import * à import global_mod.

Et le nouveau mid_access_mod.py sera:

import global_mod

class delta:
    def __init__(self):
        print global_mod.x

La raison de cela pourrait être trouvée ici .

En raison de la façon dont les références et la liaison de noms fonctionnent en Python, si vous souhaitez mettre à jour un symbole dans un module, dites foo.bar, depuis l'extérieur de ce module, et que d'autres codes d'importation "voient" ce changement, vous devez importer foo a certaine manière.

0
Chaoz

J'ai modifié l'exemple pour utiliser une liste pour x et les assignations de liste (x [0] = ..) comme suggéré dans la réponse du haut, et l'impression a renvoyé la même valeur initiale (None) .. Cela vérifie que le "from global_mod import * "est une copie, qu'elle soit modifiable ou non.

Comme suggéré dans le commentaire "import global_mod" fonctionne, si "print global_mod.x = est alors utilisé dans mid_access_mod.

0
knormoyle