La visibilité des variables globales dans les modules importés
J'ai couru dans un peu d'un mur à l'importation de modules dans un script Python. Je vais faire de mon mieux pour décrire l'erreur, pourquoi je rencontre, et pourquoi je suis attachant particulièrement à cette approche pour résoudre mon problème (que je vais décrire dans un deuxième):
Supposons que j'ai un module dans lequel j'ai défini une certaine utilité des fonctions/classes, qui se réfèrent à des entités définies dans l'espace de noms dans lequel cet auxiliaire module est importé (let "un" être une telle entité):
module1:
def f():
print a
Et puis j'ai le programme principal, où "a" est défini, dans lequel je veux importer ces utilitaires:
import module1
a=3
module1.f()
De l'exécution du programme va déclencher l'erreur suivante:
Traceback (most recent call last):
File "Z:\Python\main.py", line 10, in <module>
module1.f()
File "Z:\Python\module1.py", line 3, in f
print a
NameError: global name 'a' is not defined
Des questions similaires ont été posées dans le passé (il y a deux jours, d'uh) et plusieurs solutions ont été proposées, mais je ne pense pas vraiment que ces l'adapter à mes besoins. Voici mon contexte particulier:
Je suis en train de faire un programme en Python qui se connecte à MySQL est un serveur de base de données et affiche/modifie des données avec une interface graphique. Pour la propreté souci, j'ai défini la bande d'auxiliaires de l'utilitaire MySQL, les fonctions dans un fichier séparé. Pourtant, elles ont toutes une variable commune, qui m'avait été défini à l'origine à l'intérieur de le module utilitaires, et qui est le curseur l'objet à partir du module MySQLdb.
Plus tard, j'ai réalisé que la curseur objet (qui est utilisé pour communiquer avec le serveur de base de données) doivent être définis dans le module principal, de sorte que le module principal et de tout ce qui est importé, il peut accéder à cet objet.
Résultat final serait quelque chose comme ceci:
utilities_module.py:
def utility_1(args):
code which references a variable named "cur"
def utility_n(args):
etcetera
Et mon module principal:
program.py:
import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
Et puis, dès que j'essaie d'appeler une des fonctions utilitaires, il déclenche le fameux "nom global non définie" erreur.
Une suggestion particulière était d'avoir un "à partir du programme d'importation cur" instruction dans les services de fichier, comme ceci:
utilities_module.py:
from program import cur
#rest of function definitions
program.py:
import Tkinter, MySQLdb
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
Mais c'est cyclique d'importation ou quelque chose comme ça et, en bout de ligne, il se bloque trop. Donc ma question est:
Comment diable puis-je faire le "cur" de l'objet, défini dans le module principal, visible à ceux des fonctions auxiliaires qui sont importés en elle?
Merci pour votre temps et mes plus sincères excuses si la solution a été posté ailleurs. Je ne peux pas trouver la réponse moi-même et je n'ai pas plus d'un tour dans mon livre.
- En fonction de votre mise à jour: Vous ne voulez probablement pas une seule et même curseur de toute façon. Une seule connexion partagée, oui, mais les curseurs ne sont pas chers, et il y a souvent de bonnes raisons d'avoir plusieurs curseurs vivant à la même époque (par exemple, de sorte que vous pouvez parcourir par le biais de deux d'entre eux en prison au lieu d'avoir à
fetch_all
et itérer sur les deux listes à la place, ou tout simplement de sorte que vous pouvez avoir deux threads/greenlets/rappel-chaînes/quelle que soit l'aide de la base de données sans conflits). - De toute façon, tout ce que vous souhaitez partager, je pense que la réponse ici est de déplacer
db
(etcur
, si vous insistez) dans un module distinct que les deuxprogram
etutilities_module
importer à partir de. De cette façon, vous n'obtenez pas de dépendances circulaires (programme d'importation de modules de programme d'importations) et de la confusion qui vient avec eux.
Vous devez vous connecter pour publier un commentaire.
Globals en Python sont globales à un module, pas à travers tous les modules. (Beaucoup de gens sont confus par cela, parce que, par exemple, en C, un global est le même sur tous les fichiers de mise en œuvre, sauf si vous explicitement faire
static
.)Il existe différentes méthodes pour résoudre ce problème, selon votre cas d'utilisation.
Avant même d'entrer dans cette voie, demandez-vous si elle a vraiment besoin d'être global. Peut-être que vous voulez vraiment classe, avec
f
comme une méthode d'instance, plutôt que de simplement une fonction libre? Ensuite, vous pourriez faire quelque chose comme ceci:Si vraiment vous ne voulez mondiale, mais il est juste là pour être utilisé par
module1
, de le fixer dans ce module.D'autre part, si
a
est partagée par tout un tas de modules, le mettre quelque part d'autre, et tout le monde l'importer:... et, dans module1.py:
Ne pas utiliser un
from
l'importation, sauf si la variable est destinée à être une constante.from shared_stuff import a
de créer une nouvellea
variable initialisée à ce queshared_stuff.a
mentionnés au moment de l'importation, et ce nouveaua
variable ne serait pas affecté par des assignations à desshared_stuff.a
.Ou, dans les rares cas où vous avez vraiment besoin pour être véritablement mondiale partout, comme un builtin, l'ajouter à la builtin module. Les détails diffèrent entre Python 2.x et 3.x. En 3.x, il fonctionne comme ceci:
globals
est le cas paradigmatique de la klaxonnant excellente idée que tout le reste est construit sur (au moins sur le plan conceptuel; dans les détails, la nouvelle-classes de style sont probablement le meilleur paradigme).Comme une solution de contournement, vous pourriez envisager de définir des variables d'environnement dans la couche externe, à l'instar de ce.
main.py:
mymodule.py:
Comme une précaution supplémentaire, gérer le cas lorsque MYVAL n'est pas définie à l'intérieur du module.
Une fonction utilise les variables globales du module, c'est défini dans. Au lieu de définir
a = 3
, par exemple, vous devriez être en paramètremodule1.a = 3
. Donc, si vous voulezcur
disponibles en tant que global dansutilities_module
, ensembleutilities_module.cur
.Une meilleure solution: ne pas utiliser de variables globales. Passer les variables dont vous avez besoin dans les fonctions qui en ont besoin, ou de créer une classe permettant de regrouper toutes les données ensemble, et de le transmettre lors de l'initialisation de l'instance.
Ce post est juste une observation pour Python comportement que j'ai rencontré. Peut-être que les conseils que vous lisez ci-dessus ne fonctionnent pas pour vous si vous avez fait la même chose que j'ai fait ci-dessous.
À savoir, j'ai un module qui contient global/variables partagées (comme suggéré ci-dessus):
Ensuite, j'ai eu le module principal qui importe le partagé des choses avec:
et quelques autres modules qui en fait peuplé de ces tableaux. Ceux-ci sont appelés par le module principal. Au moment de quitter ces autres modules, je peux clairement voir que les tableaux sont remplis. Mais lors de la lecture en arrière dans le module principal, ils étaient vides. C'était plutôt étrange pour moi (bon, je suis nouveau sur le Python). Cependant, quand j'ai changer la façon dont je l'importation de la sharedstuff.py dans le module principal pour:
il a travaillé (les tableaux ont été peuplées).
Just sayin'
La méthode la plus simple solution de ce problème particulier aurait été d'ajouter une autre fonction dans le module qui aurait stocké le curseur dans une variable globale pour le module. Alors que toutes les autres fonctions pourraient l'utiliser aussi bien.
module1:
programme principal:
Depuis globales sont spécifiques au module, vous pouvez ajouter la fonction suivante pour tous les modules importés, et ensuite l'utiliser pour:
.
Puis tout ce que vous devez passer sur le courant globals est:
Puisque je n'ai pas vu cela dans les réponses ci-dessus, j'ai pensé que je voudrais ajouter ma solution simple qui est juste pour ajouter un
global_dict
argument à la fonction nécessitant l'appel du module globals, et de passer ensuite le dict dans la fonction lors de l'appel; e.g:La POO façon de le faire serait de faire de votre module de classe au lieu d'une série de unbound méthodes. Ensuite, vous pouvez utiliser
__init__
ou une méthode de définition de définir les variables à partir de l'appelant pour l'utilisation dans le module de méthodes.