Globale Variablen zwischen Dateien verwenden?

207

Ich bin etwas verwirrt darüber, wie die globalen Variablen funktionieren. Ich habe ein großes Projekt mit ungefähr 50 Dateien und muss globale Variablen für alle diese Dateien definieren.

Ich habe sie in meiner Projektdatei main.pywie folgt definiert:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

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

Ich versuche zu verwenden , myListin subfile.py, wie folgend

# ../myproject/subfile.py

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

Ein anderer Weg, den ich versucht habe, aber auch nicht funktioniert hat

# ../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])

Und drinnen hatte subfile.pyich folgendes:

# ../myproject/subfile.py

# Import globfile
import globfile

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

Aber es hat wieder nicht funktioniert. Wie soll ich das umsetzen? Ich verstehe, dass es so nicht funktionieren kann, wenn sich die beiden Dateien nicht wirklich kennen (nun, Subdatei kennt Main nicht), aber ich kann mir nicht vorstellen, wie es geht, ohne Io Writing oder Pickle zu verwenden Ich will nicht tun

Martineau
quelle
Eigentlich funktioniert Ihr zweiter Ansatz für mich ganz gut. main.py druckt "hey" korrekt aus. Können Sie genauer sagen, was Sie mir durch "es hat nicht funktioniert"?
Rodion
@rodion: Importieren von Zyklen - der Code in der Subdatei versucht, Globfile zu importieren, die sich in itś body zurück importiert
jsbueno
1
NameError: name 'myList' is not definedfrom main.pylineprint(globfile.myList[0])

Antworten:

318

Das Problem ist , dass Sie definiert myListaus main.py, aber subfile.pyes braucht zu verwenden. Hier ist ein sauberer Weg, um dieses Problem zu lösen: Verschieben Sie alle Globals in eine Datei, ich nenne diese Datei settings.py. Diese Datei ist dafür verantwortlich, Globals zu definieren und zu initialisieren:

# settings.py

def init():
    global myList
    myList = []

Als nächstes können Sie subfileGlobals importieren:

# subfile.py

import settings

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

Beachten Sie, dass subfilenicht aufgerufen wird init()- diese Aufgabe gehört zu 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

Auf diese Weise erreichen Sie Ihr Ziel und vermeiden es, globale Variablen mehrmals zu initialisieren.

Hai Vu
quelle
40
Ich mag den allgemeinen Ansatz, aber nicht das ganze init()Zeug. Module werden nur beim ersten Import ausgewertet. Daher ist es vollkommen in Ordnung, diese Variablen im Hauptteil des Moduls zu initialisieren.
Kirk Strauser
19
+1 Kirk: Ich stimme zu. Mein Ansatz verhindert jedoch den Fall, dass andere Module globals.myList ändern, bevor das Hauptprogramm gestartet wird.
Hai Vu
2
Sie sollten es etwas anderes als Globals nennen, was ein eingebauter Name ist. PyLint gibt die Warnung: "Neu definierte 'Globale' neu definieren (neu definiert-eingebaut)"
twasbrillig
Vielen Dank. Haben Sie eine Idee, wie Sie die in Eclipse PyDev auftretenden Fehler "Undefinierte Variable aus dem Import" mithilfe dieser Dateistruktur entfernen können (dh globale Variablen aus settings.py importieren)? Ich musste den Fehler in PyDev deaktivieren , was nicht ideal ist.
Franck Dernoncourt
@FranckDernoncourt Es tut mir leid, ich benutze Eclipse nicht, also bin ich noch ahnungsloser als du.
Hai Vu
92

Siehe Pythons Dokument zum Teilen globaler Variablen zwischen Modulen :

Die kanonische Möglichkeit, Informationen zwischen Modulen innerhalb eines einzelnen Programms auszutauschen, besteht darin, ein spezielles Modul zu erstellen (häufig als config oder cfg bezeichnet).

config.py:

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

Importieren Sie das Konfigurationsmodul in alle Module Ihrer Anwendung. Das Modul wird dann als globaler Name verfügbar.

main.py:

import config
print (config.x)

oder

from config import x
print (x)

Im Allgemeinen nicht aus Modulnamen importieren * . Dadurch wird der Namespace des Importeurs unübersichtlich und es wird für Linters viel schwieriger, undefinierte Namen zu erkennen.

Ogaga Uzoh
quelle
1
Lebensretter - nur für diesen Link!
ToonarmyCaptain
4
Dies scheint ein sauberer Ansatz zu sein als die akzeptierte Antwort.
JoeyC
2
Beachten Sie, dass Sie nicht xmit from config import x, sondern nur mitimport config
Yariv
1
Einfachste Lösung! Danke
user1297406
22

Sie können sich globale Python-Variablen als "Modul" -Variablen vorstellen - und als solche sind sie viel nützlicher als die traditionellen "globalen Variablen" von C.

Eine globale Variable ist tatsächlich in einem Modul definiert __dict__und kann von außerhalb dieses Moduls als Modulattribut aufgerufen werden.

Also, in Ihrem Beispiel:

# ../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])

Und:

# ../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
quelle
1
wow, normalerweise würde man erwarten, dass zwei Dateien, die sich gegenseitig importieren, in eine Endlosschleife geraten.
Nikhil VJ
2
ha Auf den ersten Blick sieht es so aus, nicht wahr? Was in def stuff () passiert, ist, dass der Import nicht ausgeführt wird, wenn die Datei geladen wird. Er wird nur ausgeführt, wenn die Funktion stuff () aufgerufen wird. Beginnend mit main importieren wir also subfile und rufen dann subfile.stuff () auf, das dann main ... no loop importiert, nur einmal in main importiert. Siehe den Hinweis im Beispiel subfile.py zu Importzyklen.
John
11

Die Verwendung from your_file import *sollte Ihre Probleme beheben. Es definiert alles so, dass es global verfügbar ist (mit Ausnahme der lokalen Variablen bei den Importen natürlich).

beispielsweise:

##test.py:

from pytest import *

print hello_world

und:

##pytest.py

hello_world="hello world!"
IT Ninja
quelle
4
Außer wenn Sie einer solchen Variablen zuweisen
jsbueno
5
Ich persönlich vermeide die Verwendung import *um jeden Preis, so dass Referenzen explizit (und nicht verwirrend) sind. Außerdem, wann haben Sie jemals tatsächlich alle " *" Referenzen in einem Modul verwendet?
ThorSummoner
19
NICHT importieren *. Ihre globalen Variablen bleiben nicht mehr synchron. Jedes Modul erhält eine eigene Kopie. Das Ändern der Variablen in einer Datei wird in einer anderen Datei nicht berücksichtigt. Es wird auch in docs.python.org/2/faq/…
Isa Hassen
8

Hai Vu Antwort funktioniert super, nur ein Kommentar:

Wenn Sie das Global in einem anderen Modul verwenden und das Global dynamisch festlegen möchten, achten Sie darauf, die anderen Module zu importieren, nachdem Sie die globalen Variablen festgelegt haben. Beispiel:

# 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
quelle
4

Ihr zweiter Versuch wird perfekt funktionieren und ist eine wirklich gute Möglichkeit, mit Variablennamen umzugehen, die global verfügbar sein sollen. In der letzten Zeile ist jedoch ein Namensfehler aufgetreten. So sollte es sein:

# ../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])

Sehen Sie die letzte Zeile? myList ist ein Attribut von globfile, nicht von subfile. Dies wird funktionieren, wie Sie wollen.

Mike

MikeHunter
quelle