it-swarm.com.de

Sichtbarkeit globaler Variablen in importierten Modulen

Ich bin auf eine Art Wand gestoßen, die Module in einem Python-Skript importiert. Ich werde mein Bestes tun, um den Fehler zu beschreiben, warum ich darauf stoße und warum ich diesen bestimmten Ansatz binde, um mein Problem zu lösen (den ich gleich beschreiben werde):

Angenommen, ich habe ein Modul, in dem ich einige Dienstprogrammfunktionen klassen definiert habe, die sich auf Entitäten beziehen, die im Namespace definiert sind, in den dieses Hilfsmodul importiert wird ("a" sei eine solche Entität):

modul 1:

def f():
    print a

Und dann habe ich das Hauptprogramm, in dem "a" definiert ist, in das ich diese Dienstprogramme importieren möchte:

import module1
a=3
module1.f()

Das Ausführen des Programms löst den folgenden Fehler aus:

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

/ - Ähnliche Fragen wurden gestellt in der Vergangenheit (vor zwei Tagen, nicht wahr) und mehrere Lösungen wurden vorgeschlagen, aber ich denke nicht wirklich, dass diese meinen Anforderungen entsprechen. Hier ist mein besonderer Kontext:

Ich versuche ein Python-Programm zu erstellen, das eine Verbindung zu einem MySQL-Datenbankserver herstellt und Daten mit einer GUI anzeigt/ändert. Aus Gründen der Übersichtlichkeit habe ich die Reihe der Hilfs-/Hilfsprogrammfunktionen für MySQL in einer separaten Datei definiert. Sie haben jedoch alle eine gemeinsame Variable, die ich ursprünglich innerhalb des Dienstprogrammmoduls definiert hatte und die das Cursor -Objekt aus dem MySQLdb-Modul ist. Ich erkennen später, dass die Cursor Objekt (die mit dem DB-Server zu kommunizieren, verwendet wird) soll im Hauptmodul definiert werden,, so dass sowohl das Hauptmodul und alles, was in sie importiert zugreifen dieses Objekt.

Das Endergebnis würde ungefähr so ​​aussehen:

utilities_module.py:

def utility_1(args):
    code which references a variable named "cur"
def utility_n(args):
    etcetera

Und mein Hauptmodul:

program.py:

import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor()  #cur is defined!
from utilities_module import *

Sobald ich versuche, eine der Dienstprogrammfunktionen aufzurufen, wird der oben genannte Fehler "globaler Name nicht definiert" ausgelöst.

Ein besonderer Vorschlag war, eine "from program import cur" -Anweisung in der Dienstprogrammdatei zu haben, wie diese:

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 *

Aber das ist zyklischer Import oder so und unter dem Strich stürzt es auch ab. Meine Frage lautet also:

Wie zum Teufel kann ich das im Hauptmodul definierte "cur" -Objekt für die Hilfsfunktionen sichtbar machen, die in es importiert werden?

Vielen Dank für Ihre Zeit und meine tiefste Entschuldigung, wenn die Lösung an anderer Stelle veröffentlicht wurde. Ich finde die Antwort einfach nicht selbst und habe keine Tricks mehr in meinem Buch.

70
Nubarke

Globals in Python sind global zu einem Modul , nicht über alle Module hinweg. (Viele Leute sind davon verwirrt, denn in C ist ein Global in allen Implementierungsdateien gleich, es sei denn, Sie machen es explizit zu static.)

Es gibt verschiedene Möglichkeiten, dies zu lösen, abhängig von Ihrem tatsächlichen Anwendungsfall.


Bevor Sie diesen Weg einschlagen, sollten Sie sich fragen, ob dies wirklich global sein muss. Vielleicht möchten Sie wirklich eine Klasse mit f als Instanzmethode und nicht nur mit einer freien Funktion? Dann könntest du so etwas machen:

import module1
thingy1 = module1.Thingy(a=3)
thingy1.f()

Wenn Sie wirklich ein globales Element wünschen, das jedoch nur von module1 verwendet werden soll, legen Sie es in diesem Modul fest.

import module1
module1.a=3
module1.f()

Wenn dagegen a von vielen Modulen gemeinsam genutzt wird, legen Sie sie an einem anderen Ort ab und lassen Sie alle ihn importieren:

import shared_stuff
import module1
shared_stuff.a = 3
module1.f()

… Und in module1.py:

import shared_stuff
def f():
    print shared_stuff.a

Nicht Verwenden Sie einen from-Import, es sei denn, die Variable soll eine Konstante sein. from shared_stuff import a würde eine neue a-Variable erstellen, die mit dem zum Zeitpunkt des Imports angegebenen shared_stuff.a initialisiert wurde, und diese neue a-Variable würde durch Zuweisungen zu shared_stuff.a nicht beeinflusst.


Oder in dem seltenen Fall, dass Sie wirklich wirklich global sein müssen, wie ein Built-In, fügen Sie es dem Built-In-Modul hinzu. Die genauen Details unterscheiden sich zwischen Python 2.x und 3.x. In 3.x funktioniert das so:

import builtins
import module1
builtins.a = 3
module1.f()
176
abarnert

Um dieses Problem zu umgehen, können Sie Umgebungsvariablen in der äußeren Ebene festlegen. 

main.py:

import os
os.environ['MYVAL'] = str(myintvariable)

mymodule.py:

import os
print os.environ['MYVAL']

Behandeln Sie als zusätzliche Vorsichtsmaßnahme den Fall, wenn MYVAL nicht im Modul definiert ist. 

5
Vishal

Eine Funktion verwendet die Globals des Moduls, das definiert in ist. Anstelle von a = 3 sollten Sie beispielsweise module1.a = 3 einstellen. Wenn Sie also cur als globale Variable in utilities_module verfügbar machen möchten, setzen Sie utilities_module.cur.

Eine bessere Lösung: Verwenden Sie keine Globals. Übergeben Sie die benötigten Variablen an die benötigten Funktionen, oder erstellen Sie eine Klasse, um alle Daten zu bündeln, und übergeben Sie sie beim Initialisieren der Instanz.

3
kindall

Dieser Beitrag ist nur eine Beobachtung für das Verhalten von Python, dem ich begegnet bin. Vielleicht funktionieren die Ratschläge, die Sie oben gelesen haben, nicht für Sie, wenn Sie dasselbe machen, was ich unten gemacht habe.

Ich habe nämlich ein Modul, das globale/gemeinsam genutzte Variablen enthält (wie oben vorgeschlagen):

#sharedstuff.py

globaltimes_randomnode=[]
globalist_randomnode=[]

Dann hatte ich das Hauptmodul, das die geteilten Sachen mit importiert:

import sharedstuff as shared

und einige andere Module, die diese Arrays tatsächlich gefüllt haben. Diese werden vom Hauptmodul aufgerufen. Beim Beenden dieser anderen Module kann ich deutlich sehen, dass die Arrays belegt sind. Aber als sie sie im Hauptmodul gelesen haben, waren sie leer. Das war ziemlich seltsam für mich (naja, ich bin neu in Python). Wenn ich jedoch die Methode ändere, importiere ich die sharedstuff.py im Hauptmodul nach:

from globals import *

es hat funktioniert (die Arrays waren gefüllt).

Ich sag bloß'

3
user3336548

Die einfachste Lösung für dieses spezielle Problem wäre gewesen, eine weitere Funktion innerhalb des Moduls hinzuzufügen, die den Cursor in einer globalen Variablen im Modul gespeichert hätte. Dann können auch alle anderen Funktionen verwendet werden.

modul 1:

cursor = None

def setCursor(cur):
    global cursor
    cursor = cur

def method(some, args):
    global cursor
    do_stuff(cursor, some, args)

hauptprogramm:

import module1

cursor = get_a_cursor()
module1.setCursor(cursor)
module1.method()
2
Chris Nasr

Da Globals modulspezifisch sind, können Sie allen importierten Modulen die folgende Funktion hinzufügen und diese dann verwenden, um:

  • Fügen Sie einzelne Variablen (im Wörterbuchformat) als globale Variablen für diese hinzu 
  • Übertragen Sie Ihre main module-Globals in diese .

addglobals = lambda x: globals (). update (x)

Dann müssen Sie nur noch aktuelle Globals weitergeben: 

importmodul

module.addglobals (globals ())

1
user2589273

Die OOP Möglichkeit, dies zu tun, besteht darin, Ihr Modul zu einer Klasse zu machen, anstatt eine Reihe ungebundener Methoden. Dann können Sie __init__ oder eine Setter-Methode verwenden, um die Variablen des Aufrufers für die Verwendung in den Modulmethoden festzulegen.

0
coyot

Da ich es in den Antworten oben nicht gesehen habe, dachte ich, ich würde meine einfache Problemumgehung hinzufügen, nämlich, der Funktion, die die Globals des aufrufenden Moduls erfordert, ein global_dict-Argument hinzuzufügen und dann beim Aufruf das Dikt in die Funktion zu übergeben. z.B:

# external_module
def imported_function(global_dict=None):
    print(global_dict["a"])


# calling_module
a = 12
from external_module import imported_function
imported_function(global_dict=globals())

>>> 12
0
Toby Petty