Seite 1 von 1
Klassen in Python: global name is not defined
Verfasst: Dienstag 7. März 2006, 11:46
von madRAM
Hallo zusammen,
ich habe ein Problem mit Klassen - wahrscheinlich ein Verständnisproblem.
Ich habe eine Klasse die auf Daten einer anderen Klasse zugreifen soll. Die erste Klasse erzeugt ein Fenster mit Buttons und so weiter und die zweite Klasse enthält lokalisierte Textelemente, für die genannten Buttons.
Locale Klasse:
Code: Alles auswählen
class localeEnv:
textElements = { "msgImageCreateRun" : { "DE" : 'Abbilderzeugung laeuft' , "EN" : 'Creating Image' }}
def __init__(self, lang=""):
self.lang = lang
def getMsgImageCreateRun(self):
return self.textElements[msgImageCreateRun[lang]]
Fensterklasse:
Code: Alles auswählen
class MeinFenster(Tkinter.Tk):
def __init__(self):
# Init
Tkinter.Tk.__init__(self)
self.imageMeldungen = Tkinter.StringVar()
self.locale = localeEnv(lang)
Wenn ich nun im Verlauf meines Programmes auf die Funktionen meiner Locale Klasse aus der Fenster Klasse zugreifen möchte erhalte ich folgende Fehlermeldung:
Code: Alles auswählen
Traceback (most recent call last):
File "./tk_menu.py", line 439, in ?
fenster = MeinFenster()
File "./tk_menu.py", line 400, in __init__
text = self.locale.getMsgImageCreateRun(),
File "./tk_menu.py", line 63, in getMsgImageCreateRun
return self.textElements[msgImageCreateRun[lang]]
NameError: global name 'msgImageCreateRun' is not defined
Ich versteh das aber nicht. Natuerlich ist kein globaler Bezeichner, aber ich rufe ihn ja auch nicht von extern au, sondern doch aus der eigenen Klasse. Oder versteh ich hier grundsätzlich was falsch???
Ps.: Natürlich sind die Code-Snippets unvollständig, ich wollte hier aber nicht einfach den ganzen Code hinposten. Sollte er für die Fehlersuche relevant sein, kann ich das ja noch nachholen.
Verfasst: Dienstag 7. März 2006, 11:51
von mr.hide
Der Fehler liegt nich an der Klasse.
Du greifst falsch auf Dictionary zu!
So gehts:
Verfasst: Dienstag 7. März 2006, 11:55
von mr.hide
Wobei ich grad sehe:
So würde ich das auf keinen Fall machen.
Suche dir eine default Sprache aus.
So kriegst du eine Exception, weil ja nachher auf das Dictionary mit dem Schlüssel lang zu gegriffen wird.
Verfasst: Dienstag 7. März 2006, 12:05
von madRAM
Leider hat das das Problem nicht gelöst. Ich habe jetzt den Zugriff auf das Dictionary entsprechend geändert, aber die Fehlermeldung ist immer noch die gleiche:
Code: Alles auswählen
Traceback (most recent call last):
File "./tk_menu.py", line 436, in ?
fenster = MeinFenster()
File "./tk_menu.py", line 397, in __init__
text = self.locale.getBtnTxtImageCreateStart(),
File "./tk_menu.py", line 60, in getBtnTxtImageCreateStart
return self.textElements[btnTxtImageCreateStart][lang]
NameError: global name 'btnTxtImageCreateStart' is not defined
Ich poste jetzt mal das ganze Script:
Code: Alles auswählen
#!/usr/bin/env python2.4
# -*- coding: iso-8859-1 -*-
#
# tk_menu.py
# ConLab
#
# Created by Christian Guenther on 3/6/06.
# Copyright (c) 2006 __MyCompanyName__. All rights reserved.
#
"""
Threaded Image creation
"""
import threading
import time
import Tkinter
import sys
#----------------------------------------------------------------------
class localeEnv:
"""
Enthaelt lokalisierte Texte fuer die Oberflaeche
"""
textElements = { "msgImageCreateRun" : { "DE" : 'Abbilderzeugung laeuft' ,
"EN" : 'Creating Image' } ,
"msgImageRestoreRun" : { "DE" : 'Abbild wird zurueck geschrieben' ,
"EN" : 'Restoring Image' } ,
"btnTxtImageCreateStart" : { "DE" : 'Start Abbilderzeugung' ,
"EN" : 'Start Imaging' } ,
"btnTxtImageCreateStop" : { "DE" : 'Stop Abbilderzeugung' ,
"EN" : 'Stop Imaging' } ,
"btnTxtImageRestoreStart" : { "DE" : 'Start Abbild zurueckschreiben' ,
"EN" : 'Start Restoring' } ,
"btnTxtImageRestoreStop" : { "DE" : 'Stop Abbild zurueckschreiben' ,
"EN" : 'Stop Restoring' } ,
"btnTxtProgramEnd" : { "DE" : 'Programmende' ,
"EN" : 'End program'}}
lang = "EN"
def __init__(self, lang="EN"):
self.lang = lang
#----------------------------------------------------------------------
def setLang(self,lang):
self.lang = lang
def getLang(self):
return self.lang
#----------------------------------------------------------------------
def getMsgImageCreateRun(self):
return self.textElements[msgImageCreateRun][lang]
def getMsgImageRestoreRun(self):
return self.textElements[msgImageRestoreRun][lang]
def getBtnTxtImageCreateStart(self):
return self.textElements[btnTxtImageCreateStart][lang]
def getBtnTxtImageCreateStop(self):
return self.textElements[btnTxtImageCreateStop][lang]
def getBtnTxtImagerestoreStart(self):
return self.textElements[btnTxtImageRestoreStart][lang]
def getBtnTxtImageRestoreStop(self):
return self.textElements[btnTxtImageRestoreStop][lang]
#----------------------------------------------------------------------
class ImageProcessing(threading.Thread):
"""
Uebernimmt das komplette Image Handling
"""
imageName = ""
imageInfo = {"imagePath" : '',
"imageDevice" : '',
"imageOS" : '',
"imageOSVersion" : '',
"imageSize" : '',
"imageVersion" : '',
"imageCreateDate" : '',
"ImageProcess" : {"imageAction" : 'create',
"imageActionActive" : 0}}
#----------------------------------------------------------------------
def __init__(self,
imageName = None,
imageInfo = {}):
"""
imageName = String
imageInfo = Dictionary{
imagePath
imageDevice
imageOS
imageOSVersion
imageSize
imageVersion
imageCreateDate
}
"""
self.imageName = imageName
if len(imageInfo) > 1:
if imageInfo.haskey(imagePath):
self.imageInfo[imagePath] = imageInfo[imagePath]
if imageInfo.haskey(imageDevice):
self.imageInfo[imageDevice] = imageInfo[imageDevice]
if imageInfo.haskey(imageOS):
self.imageInfo[imageOS] = imageInfo[imageOS]
if imageInfo.haskey(imageOSVersion):
self.imageInfo[imageOSVersion] = imageInfo[imageOSVersion]
if imageInfo.haskey(imageSize):
self.imageInfo[imageSize] = imageInfo[imageSize]
if imageInfo.haskey(imageVersion):
self.imageInfo[imageVersion] = imageInfo[imageVersion]
if imageInfo.haskey(imageCreateDate):
self.imageInfo[imageCreateDate] = imageInfo[imageCreateDate]
#-- getter und setter
def getImageName(self):
return self.imageName
def getImagePath(self):
return self.imageInfo[imagePath]
def getImageOS(self):
return self.imageInfo[imageOS]
def getImageOSVersion(self):
return self.imageInfo[imageOSVersion]
def getImageSize(self):
return self.imageInfo[imageSize]
def getImageVersion(self):
return self.imageInfo[imageVersion]
def getImageCreateDate(self):
return self.imageInfo[imageCreateDate]
def setImageName(imageName):
self.imageName = imageName
def setImageInfo(imageInfo):
if imageInfo.haskey(imagePath):
self.imageInfo[imagePath] = imageInfo[imagePath]
if imageInfo.haskey(imageOS):
self.imageInfo[imageOS] = imageInfo[imageOS]
if imageInfo.haskey(imageOSVersion):
self.imageInfo[imageOSVersion] = imageInfo[imageOSVersion]
if imageInfo.haskey(imageSize):
self.imageInfo[imageSize] = imageInfo[imageSize]
if imageInfo.haskey(imageVersion):
self.imageInfo[imageVersion] = imageInfo[imageVersion]
if imageInfo.haskey(imageCreateDate):
self.imageInfo[imageCreateDate] = imageInfo[imageCreateDate]
#--dump the device
def dumpDevice(self):
dumpString = 'dd if=' + self.imageInfo[imageDevice] + ' of=' + self.imageInfo[imagePath] + ' bs=32k'
print dumpString
self.imageInfo[ImageProcess][imageAction] = 'create'
self.imageInfo[ImageProcess][imageActionActive] = 1
#sys.exec(dumpString)
#self.imageInfo[ImageProcess][imageActionActive] = 0
#--restore the device
def restoreDevice(self):
restoreString = 'dd if=' + self.imageInfo[imagePath] + ' of=' + self.imageInfo[imageDevice] + ' bs=32k'
print restoreString
self.imageInfo[ImageProcess][imageAction] = 'restore'
self.imageInfo[ImageProcess][imageActionActive] = 1
#sys.exec(restoreString)
#self.imageInfo[ImageProcess][imageActionActive] = 0
#----------------------------------------------------------------------
class screenImageCreate(threading.Thread):
"""
Anzeige der Image Erzeugung
"""
#----------------------------------------------------------------------
def __init__(self, imageMeldungen = None):
"""
schalter = threading.Event
imageMeldungen = Rückgabe als Tkinter.StringVar, damit eine
Meldung in einem Label angezeigt werden kann.
"""
threading.Thread.__init__(self)
self.schalter = threading.Event()
self.imageMeldungen = imageMeldungen
self.canceled = False
#----------------------------------------------------------------------
def run(self):
"""
Das Image Erzeugen wird initialisiert.
Enthaelt die Steuerschleife.
"""
i = 0
while True:
# Hier wird darauf gewartet, dass der Schalter
# eingeschaltet wird.
self.schalter.wait()
if self.canceled:
break
# Statt einer Schrittmotor-Aansteuerung wird hier einfach
# ein Text an die Variable "motormeldungen" uebergeben.
# Statt mit einer Tkinter.StringVar könnte man natürlich
# auch mit print etwas anzeigen lassen.
i += 1
if self.imageMeldungen:
#self.imageMeldungen.set("Creating Image (%s)" % i)
self.imageMeldungen.set(self.locale.getMsgImageCreateRun() + " (%s)" % i)
else:
#print "Creatining Image (%s)" % i
print locale.getMsgImageCreateRun() + " (%s)" % i
time.sleep(0.5)
#----------------------------------------------------------------------
def imageCreate_start(self):
"""
Startet die Imageerzeugung
"""
self.schalter.set()
#----------------------------------------------------------------------
def imageCreate_stopp(self):
"""
Stoppt die Imageerzeugung
"""
self.schalter.clear()
#----------------------------------------------------------------------
def imageCreate_end(self):
"""
Beendet den Menubildschirm
"""
self.canceled = True
self.schalter.set()
#----------------------------------------------------------------------
class MeinFenster(Tkinter.Tk):
"""
GUI
"""
window_width = 640
window_height = 480
#----------------------------------------------------------------------
def _center(self, *args):
"""
Zentriert das Fenster
"""
xpos = (self.winfo_screenwidth() - self.winfo_width()) / 2
ypos = ((self.winfo_screenheight() - self.winfo_height()) / 2) / 100 * 90
self.wm_geometry("+%d+%d" % (xpos,ypos))
#----------------------------------------------------------------------
def window_end(self):
"""
Schaltet die Schleife aus und schliesst das Fenster
"""
self.image.imageCreate_end()
self.destroy()
#----------------------------------------------------------------------
def __init__(self):
"""
Anzeigen und initialisieren
"""
# Init
Tkinter.Tk.__init__(self)
self.imageMeldungen = Tkinter.StringVar()
# Motor initialisieren
self.image = screenImageCreate(self.imageMeldungen)
self.image.start()
self.locale = localeEnv(lang)
# Fenster und Buttons
self.config(bd = 10)
frame = Tkinter.Frame(self)
frame.title = "Boot Image Maker"
frame.pack()
Tkinter.Button(
frame,
#text = "Start",
text = self.locale.getBtnTxtImageCreateStart(),
command = self.image.imageCreate_start,
bd = 10, padx = 10, pady = 10
).grid(row = 0, column = 0)
Tkinter.Button(
frame,
#text = "Stop",
text = self.locale.getBtnTxtImageCreateStop(),
command = self.image.imageCreate_stopp,
bd = 10, padx = 10, pady = 10
).grid(row = 0, column = 1)
# Label
lab = Tkinter.Label(
self,
text = "",
textvariable = self.imageMeldungen,
bd = 10, padx = 10, pady = 10
).pack()
# Aus
Tkinter.Button(
self,
#text = "Ende",
text = self.locale.getBtnTxtProgramEnd(),
command = self.window_end,
bd = 4
).pack()
# Warten bis das Fenster angezeigt wird und dann zentrieren
self.wait_visibility()
self._center()
if __name__ == "__main__":
#-- global Spracheinstellung
lang = "DE"
fenster = MeinFenster()
Tkinter.mainloop()
sys.exit(0)
[/code]
Verfasst: Dienstag 7. März 2006, 12:08
von mr.hide
Die Fehlermeldung ist nicht die Gleiche!
Schaud dir allein mal die Zeilennummer an!
Du versuchst mit:
aus dem Dict self.textElements den Eintrag zu finden wo der Schlüssel die VARIABLE btnTxtImageCreateStart ist.
Diese Variable ist nicht definiert. Und das steht auch in der Fehlermeldung!
Dein Fehler ist dass du
statt
verwenden musst!
Verfasst: Dienstag 7. März 2006, 12:37
von madRAM
Hey mensch super jetzt funktioniert es. Ich bin aber auch manchmal beschlagen.
Das die Fehlermeldungen nicht die gleichen waren lag übrigens daran, dass ich die erste Fehlermeldung manuell editiert hatte um sie zu den CodeSnippets passend zu machen
Jetzt hab ich nur noch eine Grundsätzliche Frage:
Wie anhand des Quellcodes ja zu sehen ist besteht mein Script aus mehreren Klassen und es werden noch mehr werden. Um aus all diesen Klassen auf die Locale Methoden und Texte zugreifen zu können müsste ich in allen Klassen die Initialisierung der localeEnv wiederholen. Dies erscheint mir aber sehr ineffizient.
Meine Frage: Kann ich die Initiierung der locale Umgebung in einer Masterklasse vornehmen und dann an weitere Klassen übergeben, oder sollte ich die locale Umgebung in jeder Klasse die Ausgaben macht neu instantiieren?
Anders gefragt: WIE MACHT MAN SOWAS AUF DIE RICHTIGE ART UND WEISE???
Verfasst: Dienstag 7. März 2006, 13:02
von mr.hide
Naja was die richtige Art ist weis ich nicht.
Aber evtl. ist wenn du von der Locale erbst eine Möglichkeit.
dann hast du ja automatisch die Funktionen der localEnv ...
Verfasst: Dienstag 7. März 2006, 13:50
von madRAM
das wäre wahrscheinlich eine Möglichkeit, aber dann würde ich in jeder Klasse eine eigene locale Umgebung initialisieren - das würde dann das Umschalten der Sprache für die ganze Applikation auf einmal unmöglich machen.
Auch der Speicherbedarf würde dadurch natürlich entsprechend steigen.
Ich würde lieber die locale Umgebung zum Programmstart initialisern und das locale Objekt - vielleicht als Referenz - an alle weiteren Klassen übergeben.
Geht sowas?
Kann man etwas in der Art machen (Pseudocode):
Code: Alles auswählen
#----------------------------------------------------------------------
class MeinFenster(Tkinter.Tk, locale):
"""
GUI mit Ausgabe in entsprechender locale
"""
if __name__ == "__main__":
#-- global Spracheinstellung
lang = "DE"
locale = localeEnv()
locale.setLang(lang)
fenster = MeinFenster(locale)
[/code]
Verfasst: Dienstag 7. März 2006, 14:03
von madRAM
Habs,
meine Main function initialisiert ein locale Object und dieses Uebergebe ich an die __init_ Methoden der entsprechenden Klassen.
Ich vererbe also nicht die locale Klasse an die anderen Klassen, sondern übergebe das locale Objekt an die Konstruktoren der anderen Klassen.
Verfasst: Dienstag 7. März 2006, 21:35
von BlackJack
"Richtig" macht man Lokalisierung mit dem `gettext` Modul.