Klassen in Python: global name is not defined

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
madRAM
User
Beiträge: 14
Registriert: Sonntag 5. März 2006, 11:28
Kontaktdaten:

Dienstag 7. März 2006, 11:46

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.
mr.hide
User
Beiträge: 108
Registriert: Montag 29. August 2005, 14:02

Dienstag 7. März 2006, 11:51

Der Fehler liegt nich an der Klasse.
Du greifst falsch auf Dictionary zu!

So gehts:

Code: Alles auswählen

return self.textElements["msgImageCreateRun"][lang]
Grüße
Matthias

- Fluchen befreit von Kummer und Leid -
mr.hide
User
Beiträge: 108
Registriert: Montag 29. August 2005, 14:02

Dienstag 7. März 2006, 11:55

Wobei ich grad sehe:

Code: Alles auswählen

def __init__(self, lang=""): 
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.
Grüße
Matthias

- Fluchen befreit von Kummer und Leid -
madRAM
User
Beiträge: 14
Registriert: Sonntag 5. März 2006, 11:28
Kontaktdaten:

Dienstag 7. März 2006, 12:05

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]
mr.hide
User
Beiträge: 108
Registriert: Montag 29. August 2005, 14:02

Dienstag 7. März 2006, 12:08

Die Fehlermeldung ist nicht die Gleiche!

Schaud dir allein mal die Zeilennummer an!


Du versuchst mit:

Code: Alles auswählen

self.textElements[btnTxtImageCreateStart][lang]
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

Code: Alles auswählen

"btnTxtImageCreateStart"
statt

Code: Alles auswählen

btnTxtImageCreateStart
verwenden musst!
Grüße
Matthias

- Fluchen befreit von Kummer und Leid -
madRAM
User
Beiträge: 14
Registriert: Sonntag 5. März 2006, 11:28
Kontaktdaten:

Dienstag 7. März 2006, 12:37

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???
mr.hide
User
Beiträge: 108
Registriert: Montag 29. August 2005, 14:02

Dienstag 7. März 2006, 13:02

Naja was die richtige Art ist weis ich nicht.

Aber evtl. ist wenn du von der Locale erbst eine Möglichkeit.

Code: Alles auswählen

class ImageProcessing(threading.Thread, localEnv): 
dann hast du ja automatisch die Funktionen der localEnv ...
Grüße
Matthias

- Fluchen befreit von Kummer und Leid -
madRAM
User
Beiträge: 14
Registriert: Sonntag 5. März 2006, 11:28
Kontaktdaten:

Dienstag 7. März 2006, 13:50

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]
madRAM
User
Beiträge: 14
Registriert: Sonntag 5. März 2006, 11:28
Kontaktdaten:

Dienstag 7. März 2006, 14:03

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.
BlackJack

Dienstag 7. März 2006, 21:35

"Richtig" macht man Lokalisierung mit dem `gettext` Modul.
Antworten