Vous utilisez des variables globales entre les fichiers?

209

Je suis un peu confus quant au fonctionnement des variables globales. J'ai un grand projet, avec environ 50 fichiers, et je dois définir des variables globales pour tous ces fichiers.

Ce que j'ai fait, c'est de les définir dans mon main.pyfichier de projets , comme suit:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

J'essaie d'utiliser myListdans subfile.py, comme suit

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
    globals()["myList"].append("hey")

Une autre façon j'ai essayé, mais ça n'a pas marché non plus

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

Et à l'intérieur subfile.pyj'avais ceci:

# ../myproject/subfile.py

# Import globfile
import globfile

# Save "hey" into myList
def stuff():
    globfile.myList.append("hey")

Mais encore une fois, cela n'a pas fonctionné. Comment dois-je mettre cela en œuvre? Je comprends que cela ne peut pas fonctionner comme ça, quand les deux fichiers ne se connaissent pas vraiment (enfin le sous-fichier ne sait pas principal), mais je ne peux pas penser à comment le faire, sans utiliser l'écriture io ou le pickle, qui Je ne veux pas faire.

martineau
la source
En fait, votre deuxième approche fonctionne très bien pour moi. main.py imprime correctement "hey". Pouvez-vous être plus précis sur ce que vous me dites "ça n'a pas marché"?
rodion
@rodion: cycles d'importation - le code dans le sous-fichier essaie d'importer le fichier global, qui dans son corps se
réimporte
1
NameError: name 'myList' is not definedde la main.pyligneprint(globfile.myList[0])

Réponses:

321

Le problème est que vous avez défini myListde main.py, mais subfile.pydoit l' utiliser. Voici une façon propre de résoudre ce problème: déplacer tous les globaux vers un fichier, j'appelle ce fichier settings.py. Ce fichier est chargé de définir les globaux et de les initialiser:

# settings.py

def init():
    global myList
    myList = []

Ensuite, vous subfilepouvez importer des globaux:

# subfile.py

import settings

def stuff():
    settings.myList.append('hey')

Notez que subfilecela n'appelle pas init()- cette tâche appartient à main.py:

# main.py

import settings
import subfile

settings.init()          # Call only once
subfile.stuff()         # Do stuff with global var
print settings.myList[0] # Check the result

De cette façon, vous atteignez votre objectif tout en évitant d'initialiser les variables globales plus d'une fois.

Hai Vu
la source
41
J'aime l'approche générale, mais pas l'ensemble init(). Les modules ne sont évalués que la première fois qu'ils sont importés, il est donc parfaitement correct d'initialiser ces variables dans le corps du module.
Kirk Strauser
19
+1 Kirk: Je suis d'accord. Cependant, mon approche empêche le cas où d'autres modules modifient globals.myList avant le démarrage du programme principal.
Hai Vu
2
Vous devriez l'appeler autre chose que globals, qui est un nom intégré. PyLint donne l'avertissement: "Redéfinir les" globaux "intégrés (intégré-redéfini)"
twasbrillig
Merci. Avez-vous une idée de la façon de supprimer les erreurs «Variable non définie de l'importation» qui apparaissent dans Eclipse PyDev en utilisant cette structure de fichier (c'est-à-dire en important des variables globales à partir de settings.py)? J'ai dû désactiver l'erreur dans PyDev , ce qui n'est pas idéal.
Franck Dernoncourt
@FranckDernoncourt Je suis désolé, je n'utilise pas Eclipse donc je suis encore plus désemparé que vous.
Hai Vu
94

Voir le document de Python sur le partage de variables globales entre les modules :

La manière canonique de partager des informations entre les modules d'un même programme consiste à créer un module spécial (souvent appelé config ou cfg).

config.py:

x = 0   # Default value of the 'x' configuration setting

Importez le module de configuration dans tous les modules de votre application; le module devient alors disponible en tant que nom global.

main.py:

import config
print (config.x)

ou

from config import x
print (x)

En général, n'utilisez pas depuis l' importation de nom de module * . Cela encombre l'espace de noms de l'importateur et rend beaucoup plus difficile pour les linters de détecter les noms non définis.

Ogaga Uzoh
la source
1
Gareautrain - juste pour ce lien!
toonarmycaptain
4
Cela semble être une approche plus propre que la réponse acceptée.
JoeyC
2
Notez que vous ne pouvez pas définir l' xutilisation from config import x, uniquement en utilisantimport config
Yariv
1
Solution la plus simple! Merci
user1297406
22

Vous pouvez considérer les variables globales Python comme des variables "module" - et en tant que telles, elles sont beaucoup plus utiles que les "variables globales" traditionnelles de C.

Une variable globale est en fait définie dans un module __dict__et est accessible depuis l'extérieur de ce module en tant qu'attribut de module.

Donc, dans votre exemple:

# ../myproject/main.py

# Define global myList
# global myList  - there is no "global" declaration at module level. Just inside
# function and methods
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

Et:

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
     # You have to make the module main available for the 
     # code here.
     # Placing the import inside the function body will
     # usually avoid import cycles - 
     # unless you happen to call this function from 
     # either main or subfile's body (i.e. not from inside a function or method)
     import main
     main.mylist.append("hey")
jsbueno
la source
1
wow, normalement, on s'attendrait à ce que deux fichiers s'important pour entrer dans une boucle infinie.
Nikhil VJ
2
ha À première vue, c'est comme ça, n'est-ce pas? Ce qui se passe dans le def stuff (), c'est que l'importation ne s'exécute pas lorsque le fichier se charge .. il ne s'exécute que lorsque la fonction stuff () est appelée. Donc, en commençant par main, nous importons le sous-fichier, puis appelons subfile.stuff () qui importe ensuite main ... pas de boucle, il suffit d'importer une fois dans main. Voir la note dans l'exemple subfile.py sur les cycles d'importation.
John
11

En utilisant from your_file import * devrait résoudre vos problèmes. Il définit tout pour qu'il soit globalement disponible (à l'exception des variables locales dans les importations bien sûr).

par exemple:

##test.py:

from pytest import *

print hello_world

et:

##pytest.py

hello_world="hello world!"
IT Ninja
la source
4
Sauf si vous attribuez à une de ces variables
jsbueno
5
Personnellement, j'évite import *à tout prix d'utiliser des références afin que les références soient explicites (et ne prêtent pas à confusion). D'ailleurs, quand avez-vous réellement utilisé toutes les *références dans un module?
ThorSummoner
19
N'IMPORTEZ PAS *. Vos variables globales ne resteront plus synchronisées. Chaque module reçoit sa propre copie. La modification de la variable dans un fichier ne se reflétera pas dans un autre. Il est également mis en garde contre dans docs.python.org/2/faq/…
Isa Hassen
8

La réponse Hai Vu fonctionne très bien, juste un commentaire:

Si vous utilisez le global dans un autre module et que vous souhaitez définir le global de manière dynamique, faites attention à importer les autres modules après avoir défini les variables globales, par exemple:

# settings.py
def init(arg):
    global myList
    myList = []
    mylist.append(arg)


# subfile.py
import settings

def print():
    settings.myList[0]


# main.py
import settings
settings.init("1st")     # global init before used in other imported modules
                         # Or else they will be undefined

import subfile    
subfile.print()          # global usage
lastboy
la source
4

Votre deuxième tentative fonctionnera parfaitement et est en fait un très bon moyen de gérer les noms de variables que vous souhaitez avoir disponibles globalement. Mais vous avez une erreur de nom dans la dernière ligne. Voici comment cela devrait être:

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

Voir la dernière ligne? myList est un attr de globfile, pas de sous-fichier. Cela fonctionnera comme vous le souhaitez.

Mike

MikeHunter
la source