aus Submodul auf globale Variable in __main__ zugreifen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
milki
User
Beiträge: 4
Registriert: Sonntag 25. Januar 2009, 15:47
Wohnort: Erfurt

Mittwoch 25. Februar 2009, 16:26

Hallo,

Ich möchte ein Programm aufräumen und dabei einige Klassen in Module verschieben. Allerdings gibt es eine kleine Abhängigkeit zum Hauptprogramm.

Es gibt so ein gobales Konfigurations-obj, auf das einige der Klassen/Objekte(/Module) mitunter zugreifen müssen. Sieht ungefähr so aus:

Code: Alles auswählen

if (__name__ == "__main__"):
    conf = Config()   # liest .ini ein

#-- in Objekten/Modulen dann:
    print conf.option1
    print conf.play.option2
Als globales Objekt find ich das wesentlich nützlicher. Ansonsten müsste man ja die ganzen evtl. benötigten Optionen zusammensuchen und an alle anderen Objekte als __init__-Parameter übergeben -- oder das conf-Objekt selbst mehrfach herumreichen.

Wenn ich jetzt aber die Klassen in Module auslagere, hab ich von dort ja keinen Zugriff mehr auf die Variable "conf" im Hauptprogramm. Die Module haben alle ihren eigenen Namensraum, und mit "global" kommt man da ja offenbar nicht raus.

Natürlich könnte ich das conf-Modul einfach in den anderen Modulen laden, dort conf=Config() nochmal separat initialisieren. Allerdings hätt ich dann ein halbes Dutzend Kopien davon, und nur die Instanz im Hauptprogramm wäre wirklich aktuell. (Es gibt ein Konfigurationsmenü.)

Wie kann ich denn das eleganter lösen?
Gibt es sowas wie eine Referenz auf das Hauptprogramm? ("__main__" ist ja nur ein Beschreibungsname, aber selbst kein Objekt)

Hab mir überlegt das conf-Objekt vielleicht in die Module zu "injizieren":

Code: Alles auswählen

    import module1
    module1.conf = conf
    import module2
    module2.conf = conf
    import module3
    module3.conf = conf
Hmm, geht. Das ist scheinbar ein stabiler Workaround. Aber gibt es denn eine andere Standardlösung für solche Fälle?
DasIch
User
Beiträge: 2452
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Mittwoch 25. Februar 2009, 16:41

Du kannst mit weakrefs eine Liste aller Instanzen des Konfiguration Objektes haben die du updatest sollte sich die Konfiguration verändern.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Mittwoch 25. Februar 2009, 17:05

Gibt es sowas wie eine Referenz auf das Hauptprogramm?("__main__" ist ja nur ein Beschreibungsname, aber selbst kein Objekt)
Warum sollte der Name "__main__" etwas extra-besonderes sein?
Wir sind hier doch bei Python, also probieren wir einfach das offensichtlichste aus :lol: :

Code: Alles auswählen

#Datei test1.py
#! /usr/bin/env python
# coding:utf-8
TEST = ["Hallo", "Welt"]
import test2

test2.foo()
print test2.bar

Code: Alles auswählen

#Datei test2.py
import __main__ as main
from __main__ import TEST
bar = TEST[:]
def foo():
    print dir(main)
Das funktioniert zumindest mal (Vorsicht bei "circular imports" d.h. wenn beide Module Objekte aus dem jeweils anderen brauchen, während sie importiert werden).

hth, Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Mittwoch 25. Februar 2009, 17:59

Stelle in dem Config-Modul eine Funktion zur Verfügung, die dir immer dieselbe Instanz zurückgibt und rufe die immer auf, anstatt immer eine neu zu instanzieren.

Gruß,
Manuel
BlackJack

Mittwoch 25. Februar 2009, 21:21

@milki: Lagere einfach nicht nur die Klassen in andere Module aus, sondern auch die Konfiguration in ein eigenes Modul. Das kannst Du dann überall importieren und hast immer Zugriff auf das selbe Config-Objekt.
milki
User
Beiträge: 4
Registriert: Sonntag 25. Januar 2009, 15:47
Wohnort: Erfurt

Mittwoch 25. Februar 2009, 22:16

Wow. So viele Möglichekeiten.
Danke für eure Antworten!!

BlackJack: Ich hatte die Config-Klasse sogar schon in ein eigenes Modul gepackt. Und jetzt hab ich einfach mal die Idee mit der einen Instanz von helduel umgesetzt:

Code: Alles auswählen

# Modul config.py
def Config():
    global conf_instance
    try:
        return conf_instance
    except:
        conf_instance = ConfigDict()
        return conf_instance
Funktioniert.

Irgendwie hat es zwar nur mit try/except funktioniert -- Eine vordefinierte Variable in dem Modul wollte nicht so recht. Aber das muss ich nochmal in Ruhe ausprobieren...

Auf jeden Fall haben Module ihren eigenen Namensraum und der wird nur ein einziges mal initialisiert. Lustig.


b.esser-wisser:
Das Beispiel hab ich gleich mal ausprobiert. Funktioniert wie erhofft. Glücklicherweise hab ich in der Python-Doku aber schon gelesen daß man besser keine Module über Kreuz lädt - deswegen mach ich das auch nich..!! :lol: hehe
Also in meinem Fall passt das eh nicht so gut, weil das Hauptprogramm doch noch relativ groß ist. Aber gut zu wissen, daß man es könnte!
Und __main__ existiert also doch irgendwo als richtiges Objekt.
http://mail.python.org/pipermail/python ... 37819.html
milki
User
Beiträge: 4
Registriert: Sonntag 25. Januar 2009, 15:47
Wohnort: Erfurt

Mittwoch 25. Februar 2009, 22:27

DasIch hat geschrieben:Du kannst mit weakrefs eine Liste aller Instanzen des Konfiguration Objektes haben die du updatest sollte sich die Konfiguration verändern.
Das hab ich mir auch mal angeguckt. http://docs.python.org/library/weakref.html
Nur eine Instanz-Liste find ich hier vor lauter Funktionen nicht.

Aber für mein conf-Objekt wär das eh overkill. Ich glaub weakref könnt ich eher verwenden für ein paar große Listen/Dicts im Programm. Hab da so ne Art Zwischenspeicher, und dann müsst ich mich da nicht selbst ums Finden und Löschen alter Werte kümmern..
Kelhim
User
Beiträge: 16
Registriert: Donnerstag 17. Mai 2007, 13:18
Wohnort: Köln

Mittwoch 25. Februar 2009, 23:12

Könntest du nicht so was probieren?

Code: Alles auswählen

# modul1.py
import config
# tu was

Code: Alles auswählen

# modul2.py
import config
# tu was
config wäre dann in jedem Modul dasselbe, selbst wenn du noch Veränderungen an config vornehmen solltest, da Python beim Import immer prüft, ob das Modul nicht bereits vorher importiert wurde. Wenn der Import nicht in einer Klasse oder Funktion verpackt ist, gilt er global im jeweiligen Modul (also bei einem Import in jedem Modul überall). Bei vor Programmaufruf bestehenden Einstellungen, die sich ändern können, aber in jedem Modul berücksichtigt werden sollen, sehr nützlich.
BlackJack

Mittwoch 25. Februar 2009, 23:57

@milki: Warum so kompliziert?

Code: Alles auswählen

# Modul config.py
conf = ConfigDict()
milki
User
Beiträge: 4
Registriert: Sonntag 25. Januar 2009, 15:47
Wohnort: Erfurt

Donnerstag 26. Februar 2009, 00:21

Ja, das ist sogar der aktuelle Stand.

Ich hab da noch was im config-Modul vereinfacht. Statt dem Singletondingsi, hab ich da einfach gleich eine Instanz von der ursprüngichen Config-Klasse erzeugt:

Code: Alles auswählen

# config.py
class ConfigDict(object):
    ...
conf = ConfigDict()
Und jetzt binde ich das config-Modul im Hauptprogramm und in allen anderen Modulen einfach folgendermaßen ein:

Code: Alles auswählen

# module[123].py
from config import conf
Damit existiert im config-Modul einmalig eine Instanz des Objekts, und in allen Modulen, wo ich es brauche, hab ich eine Referenz darauf.

Scheint mir die sauberste Lösung zu sein.
DasIch
User
Beiträge: 2452
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Donnerstag 26. Februar 2009, 23:23

Ich hab mal ein Beispiel für eine Config mit weakref gemacht http://paste.pocoo.org/show/105653/. In Config.__init__ würde man natürlich die Daten aus einer Datei oder so auslesen und in ConfigTransaction.commit da wieder speichern.
Antworten