Hallo,
habe gestern ein kleines Konvertierungstool für meine Arbeitsgruppe geschrieben. Als bisheriger PHP-Freund habe ich auf Python umgesattelt, weil ich hier GUI-Unterstützung habe. GUI ist aber für eine sinnvolle Nutzung des Tools Pflicht.
Ich bin also absoluter Python-Neuling und auch sonst eher nur Gelegenheitsskripter. Nun muss ich aber ein GUI anfertigen - besser gestern als heute - und möchte dabei das Layout von der Funktion trennen.
Als OO-Ansatz hatte ich mir erst überlegt eine Klasse anzulegen mit dem ganzen Layout und leeren Methodenrümpfen für die Aktionen (z.B. beiMausklick()) und diese Methoden dann in einer Unterklasse zu überschreiben bzw. mit Funktion zu füllen.
Dann kann ich aber von der Subklasse z.B. nicht mehr auf die Widgetkonfiguration zugreifen (z.B. button.config(text="Buttontext")).
Wie müsste ein OOP-Ansatz für die Trennung von Layout und Funktion mit Tkinter aussehen.
Ich könnte sicherlich noch ganz viel dazu lesen, aber ich brauche ja wahrscheinlich nur einen kleinen "Anstoß" und die Zeit drängt etwas.
Kann mir bitte jemand einen kleinen Codeblock geben, der mir das Prinzip klarmacht.
Vielen Dank.
OOP Ansatz zur Trennung von GUI Layout und Funktion
Vielen Dank schonmal. Da habe ich aber doch noch Fragen:
Dieses Listing war es wohl auf welches Du mich aufmerksam machen wolltest:
http://ubuntuusers.de/paste/11311/
Demnach wird das GUI in der Klasse MainGui() definiert. Der Aufruf und die Bedienung scheint vor allem durch TkApp() bestimmt zu sein. DataBook() scheint nur die Daten zu handeln und Main() habe ich jetzt noch nicht ganz verstanden. Unter anderem weil ich manche Funktionen nicht nachvollziehen kann. Ich kann z.B. nirgends etwas wie pack() od. grid() finden, was doch für die Anzeige der Widgets wesentlich ist - oder?
Zeile 443: nameGet = self.maingui._entry_1.get()
Wo ist denn die Methode get() definiert? Ich kenne da bisher ähnlich eigentlich nur cget().
Überhaupt ist doch _xxx_ eher als privat anzusehen. Warum wird es dann genutzt?
Dieses Listing war es wohl auf welches Du mich aufmerksam machen wolltest:
http://ubuntuusers.de/paste/11311/
Demnach wird das GUI in der Klasse MainGui() definiert. Der Aufruf und die Bedienung scheint vor allem durch TkApp() bestimmt zu sein. DataBook() scheint nur die Daten zu handeln und Main() habe ich jetzt noch nicht ganz verstanden. Unter anderem weil ich manche Funktionen nicht nachvollziehen kann. Ich kann z.B. nirgends etwas wie pack() od. grid() finden, was doch für die Anzeige der Widgets wesentlich ist - oder?
Zeile 443: nameGet = self.maingui._entry_1.get()
Wo ist denn die Methode get() definiert? Ich kenne da bisher ähnlich eigentlich nur cget().
Überhaupt ist doch _xxx_ eher als privat anzusehen. Warum wird es dann genutzt?
@boid: Wenn Du GUI und Funktionalität trennen willst, dann schreib am besten erst einmal die Funktionalität komplett ohne GUI.
Wenn das fertig und getestet ist, kannst Du eine GUI drauf setzen.
`get()` ist dem Fall eine Methode von Tkinter-Entries.
Wenn das fertig und getestet ist, kannst Du eine GUI drauf setzen.
`get()` ist dem Fall eine Methode von Tkinter-Entries.
Joo, das ist ja mein Problem.
Ich habe eine Klasse die die Datei handelt.
Eine weitere fügt die Daten zusammen (damit die Konvertierungen mehrerer Dateien in einer Excel-Tabelle zusammengefasst werden können).
Nun braucht die Arbeitsgruppe noch ein GUI. Nur wie mache ich das? Ich würde es schon irgendwie hinkriegen, aber ich möchte es eben gleich richtig und als OOP machen.
Das GUI selbst ist nicht schwer. 1 Listbox, 1 Dateiauswahl, 3 Radiobuttons würdens schon tun.
Ich habe bisher mehreres versucht und das beste scheint mir zu sein das GUI einfach in eine Klasse zu packen und damit ein GUI-Object zu instanzieren. Den Ansatz mit der Vererbung habe ich schon wieder verworfen. Trotzdem, weder so noch so erhalte ich die gleiche Funktionalität die ich habe wenn ich die einzelnen Handlungsroutinen direkt mit dem GUI verküpfe. Mit Handlung meine ich nicht die eigentliche Konvertierung, sondern das z.B. das Trennzeichen nach Auswahl der Listbox eben als Komma gesetzt wird. Oder das Öffnen des Dateiauswahldialoges nach klicken des entsprechenden Buttons.
Ich habe eine Klasse die die Datei handelt.
Eine weitere fügt die Daten zusammen (damit die Konvertierungen mehrerer Dateien in einer Excel-Tabelle zusammengefasst werden können).
Nun braucht die Arbeitsgruppe noch ein GUI. Nur wie mache ich das? Ich würde es schon irgendwie hinkriegen, aber ich möchte es eben gleich richtig und als OOP machen.
Das GUI selbst ist nicht schwer. 1 Listbox, 1 Dateiauswahl, 3 Radiobuttons würdens schon tun.
Ich habe bisher mehreres versucht und das beste scheint mir zu sein das GUI einfach in eine Klasse zu packen und damit ein GUI-Object zu instanzieren. Den Ansatz mit der Vererbung habe ich schon wieder verworfen. Trotzdem, weder so noch so erhalte ich die gleiche Funktionalität die ich habe wenn ich die einzelnen Handlungsroutinen direkt mit dem GUI verküpfe. Mit Handlung meine ich nicht die eigentliche Konvertierung, sondern das z.B. das Trennzeichen nach Auswahl der Listbox eben als Komma gesetzt wird. Oder das Öffnen des Dateiauswahldialoges nach klicken des entsprechenden Buttons.
Das klingt nach einer einfachen GUI-Klasse wo man die verschiedenen Einstellungen vornehmen kann und ein "Go"-Button, dessen `command` die Einstellungen von der GUI abfragt und die anderen Objekte entsprechend erzeugt und "startet". So etwas sollte man nicht komplizierter machen, als es ist.
Ja, nun ist es einfach. Aber wenn es mal komplizierter werden sollte wüßte ich doch schon gern was die grundlegendsten Richtlinien sind.
Es ist z.B. gut möglich das diese kleine Tool weiter wächst - auch wenn das dann weniger eilt. Ich möchte dann aber nicht nochmal den ganzen Code erstmal aufräumen müssen. Das habe ich eine Weile gemacht nachdem ich mich besser mit PHP auskannte und das möchte ich nicht nochmal machen.
Python kenne ich praktisch erst seit einem Tag. Was aber nicht heißt das ich null Ahnung habe. Ich habe halt vor allem bisher noch keine GUIs gemacht.
Würdest Du die GUI eher vererben oder eher instanzieren oder sonstwas und warum?
Es ist z.B. gut möglich das diese kleine Tool weiter wächst - auch wenn das dann weniger eilt. Ich möchte dann aber nicht nochmal den ganzen Code erstmal aufräumen müssen. Das habe ich eine Weile gemacht nachdem ich mich besser mit PHP auskannte und das möchte ich nicht nochmal machen.
Python kenne ich praktisch erst seit einem Tag. Was aber nicht heißt das ich null Ahnung habe. Ich habe halt vor allem bisher noch keine GUIs gemacht.
Würdest Du die GUI eher vererben oder eher instanzieren oder sonstwas und warum?
-
- User
- Beiträge: 419
- Registriert: Sonntag 3. September 2006, 15:11
- Wohnort: in den weiten von NRW
- Kontaktdaten:
In den meisten Fällen ist es so:
Zuerst schreibst du die Datenklasse(n). Wenn alles läuft, kommt die Gui drauf: Diese sollte, da sie Events verarbeiten muss, die "oberste" Klasse sein. Du kannst also in deiner GUI-Klasse entweder eine Instanz deiner (Haupt)Datenklasse erzeugen und die Buttons ect. an deren Methoden binden, oder aber von der Datenklasse erben, dann hast du alles getrennt und doch zusammen (direkter Zugriff auf alles).
Wie du das machst kannst du dir selbst überlegen, es kommt halt darauf an, wie sehr GUI und Datenklasse zusammengehören.
Zuerst schreibst du die Datenklasse(n). Wenn alles läuft, kommt die Gui drauf: Diese sollte, da sie Events verarbeiten muss, die "oberste" Klasse sein. Du kannst also in deiner GUI-Klasse entweder eine Instanz deiner (Haupt)Datenklasse erzeugen und die Buttons ect. an deren Methoden binden, oder aber von der Datenklasse erben, dann hast du alles getrennt und doch zusammen (direkter Zugriff auf alles).
Wie du das machst kannst du dir selbst überlegen, es kommt halt darauf an, wie sehr GUI und Datenklasse zusammengehören.
Ok, das heißt aber das ich die GUI-spezifischen Handlungen nicht vom GUI trennen kann - oder?
Ich meine das so (vergleich mit einem CMS):
- es gibt einmal das was das Programm tun soll (Plugin eines CMS)
- es gibt das Layout des GUIs (HTML-Ausgabe)
- und es gibt die Funktionalität des GUIs (CMS selbst)
Ich kann also mit Tkinter die Programmlogik vom GUI kapseln, aber nicht die GUI-Logik vom GUI-Layout?
Ich meine das so (vergleich mit einem CMS):
- es gibt einmal das was das Programm tun soll (Plugin eines CMS)
- es gibt das Layout des GUIs (HTML-Ausgabe)
- und es gibt die Funktionalität des GUIs (CMS selbst)
Ich kann also mit Tkinter die Programmlogik vom GUI kapseln, aber nicht die GUI-Logik vom GUI-Layout?
-
- User
- Beiträge: 419
- Registriert: Sonntag 3. September 2006, 15:11
- Wohnort: in den weiten von NRW
- Kontaktdaten:
Du kanns die Gui natürlich auch nochmal teilen. Das ist aber etwas übertrieben, wenn du keine sehr, sehr große Klasse hast. Zum einen kannst du die Gui in verschiedene Klassen unterteilen, zum anderen kannst du Metaklassen schreiben, die auf die Attribute und Methoden der EndGuiKlasse zugreifen, selbs t also nicht lauffähig sind. Das ist aber wie gesagt schon recht kompliziert und bei normalen GUIs eher verwirrend als empfehlenswert.
Ok, es geht also doch. Habe demnach bloß noch nicht rausbekommen wie.Metaklassen schreiben, die auf die Attribute und Methoden der EndGuiKlasse zugreifen, selbs t also nicht lauffähig sind. Das ist aber wie gesagt schon recht kompliziert und bei normalen GUIs eher verwirrend als empfehlenswert.
Ich lese aber auch das es sinnvoller ist bei in absehbarer Zeit überschaubaren GUI ruhig GUI-Logik und Layout in einer Klasse zu kapseln. Weil es sonst nicht leichter, sondern den gegebenen Umständen entsprechend schwerer wird.
Nun denn OOP generell und speziell bei Python werde ich wohl noch üben müssen. Ich habe es bei Vererbung z.B. noch nicht hinbekommen eine definierte Methode der Oberklasse in der Unterklasse nutzen zu können. Es geht halt immer nur zu überschreiben oder über einen Methodenaufruf des instanzierten Objektes der Unterklasse.
Was gilt es eigentlich bei py2exe mit Tkinter zu beachten? Das wäre dann der letzte Knackpunkt.
Hier mein bisheriger Code (werde eventuell weitere bei irgendeinem Paste-Dienst einstellen):
Code: Alles auswählen
import tempfile
import ConfigParser
import struct
import os
import glob
class Dat(object):
"""
Die *.dat-Datei als Objekt
@param datPath: Der Dateipfad der *.dat-Datei
"""
Count = 0 # Anzahl der zu konvertierenden *.dat-Dateien
def __init__(self, datPath):
self.datPath = datPath # Dateipfad
self.f = open(self.datPath, 'rb') # *.dat-Dateihandle
Dat.Count += 1
self.header = self.readHeader()
self.data = self.readData()
self.f.close()
def __del__(self):
Dat.Count -= 1
def readHeader(self):
datBytePosition = 0
tmp = tempfile.TemporaryFile()
while True:
line = self.f.readline()
datBytePosition = datBytePosition + len(line)
tmp.write(line)
if line.strip() == "[DATA]":
datDataStart = datBytePosition + 8
break
datHeader = ConfigParser.SafeConfigParser()
tmp.seek(0)
datHeader.readfp(tmp, "r")
tmp.close()
datHeader.set("DATA", "XSTART", str(datDataStart))
return datHeader
def readData(self):
datXData = ()
datYData = ()
datZData = ()
self.f.seek(int(self.header.get("DATA", "XSTART")))
for i in range(int(self.header.get("GENERAL", "NPOINTS"))):
datXData += (self.byteToFloat(self.f.read(4)),)
#print str(self.f.tell()) + ":" + str(i) + " " + str(self.byteToFloat(self.f.read(4)))
#print datXData
self.header.set("DATA", "YSTART", str(self.f.tell()+10))
self.f.seek(int(self.header.get("DATA", "YSTART")))
for i in range(int(self.header.get("GENERAL", "NPOINTS"))):
datYData += (self.byteToFloat(self.f.read(4)),)
datData = (tuple(datXData), tuple(datYData), tuple(datZData))
return datData
def byteToFloat(self, bytearray):
"""
Rechnet jeweils 4 bytes in Little-Endian Order (Windows) in float um
@param bytearray: String aus 4 Bytes
"""
return struct.unpack("f", bytearray)[0]
def getData(self, axis):
"""
@param axis: "X" od. "Y"
"""
if axis == "Y":
return self.data[1]
else:
return self.data[0]
def getHeader(self):
return self.header
class Dat2CSV(object):
def __init__(self):
self.allData = ()
self.maxDataLines = 0
self.maxDataFiles = ""
self.delim = ";"
def __del__(self):
return None
def addDatFile(self, f):
"""
@param f: Dateipfad absolut od. relativ "./datei.dat"
"""
csv = Dat(f)
currentDatFile = (f[len(os.path.dirname(f))+1:]) # Filename
currentDatDir = (os.path.dirname(f)) # Verzeichnispfad
currentAllData = (currentDatFile, currentDatDir, csv.getData("X"), csv.getData("Y"))
self.allData += (currentAllData,)
self.maxDataFiles = int(Dat.Count)+1
if len(self.allData[0][2])+1 > self.maxDataLines:
self.maxDataLines = len(self.allData[0][2])
def convAddFiles(self):
"""
Konvertiert alle Dateien in eine CSV mit nur einer X-Spalte aus der ersten Datei
"""
csvOutName = str(self.allData[0][1]) + "/convsumDat2CSV.csv"
csvOut = open(csvOutName, "w")
csvHeaderLine = "X" + self.delim
for l in range (self.maxDataFiles):
csvHeaderLine = csvHeaderLine + self.allData[l][0] + self.delim
csvOut.write(csvHeaderLine + "\n")
# Schreiben der Spalte
for l in range (self.maxDataLines):
# X-Werte
csvLine = str(self.allData[0][2][l]) + self.delim
# Schreiben der Zeile
for f in range (self.maxDataFiles):
if l < len(self.allData[f][3]):
csvLine += str(self.allData[f][3][l]) + self.delim
else:
csvLine += self.delim
csvOut.write(csvLine + "\n")
csvOut.close()
print "Die Ausgabe ist nach \"" + csvOutName + "\" erfolgt"
def convFile(self):
for f in range(self.maxDataFiles):
csvOutName = str(self.allData[f][1]) + "/" + str(self.allData[f][0]) + ".csv"
csvOut = open(csvOutName, "w")
csvHeaderLine = "X" + self.delim + self.allData[f][0]
csvOut.write(csvHeaderLine + "\n")
for i in range(len(self.allData[f][2])):
csvLine = str(self.allData[f][2][i]) + self.delim
csvLine += str(self.allData[f][3][i])
csvOut.write(csvLine + "\n")
csvOut.close()
print "Die Ausgabe ist nach \"" + csvOutName + "\" erfolgt"
class Menu(object):
"""
Bedienungsmenu
@author XXX
@date 2008-01-26
"""
def __init__(self):
print "------------------------------------------------";
print "Konvertiert *.dat von ZEISS Spektrometern in CSV";
print "XXXX";
print "------------------------------------------------";
print "";
# Konvertierungmodus
print "Alles in eine CSV (1) oder getrennt (2)?";
convMode = raw_input()
if convMode != "1" and convMode != "2":
convMode = "1"
# Konvertierungsort mit den Dateien
print "Pfad zu den *.dat:";
convPath = raw_input()
# Und los gehts
self.dirListing(convMode, convPath)
def dirListing(self, convMode, convPath):
dat = Dat2CSV()
datFiles = glob.glob(convPath + '*.dat')
for datFile in datFiles:
print datFile
dat.addDatFile(datFile)
# Konvertiert
if convMode == "1":
dat.convAddFiles()
if convMode == "2":
dat.convFile()
del dat
main = Menu()
-
- User
- Beiträge: 419
- Registriert: Sonntag 3. September 2006, 15:11
- Wohnort: in den weiten von NRW
- Kontaktdaten:
oder was? Einfach die Methode der Überklasse aufrufen und self übergeben.boid hat geschrieben:Ich habe es bei Vererbung z.B. noch nicht hinbekommen eine definierte Methode der Oberklasse in der Unterklasse nutzen zu können. Es geht halt immer nur zu überschreiben oder über einen Methodenaufruf des instanzierten Objektes der Unterklasse.
Du musst die ganzen tk-Sachen mit reinpacken, wenn das nicht automatisch passiert, was aber eigentlich geschehen sollte. Siehe auchboid hat geschrieben:Was gilt es eigentlich bei py2exe mit Tkinter zu beachten? Das wäre dann der letzte Knackpunkt.
http://www.py2exe.org
http://www.py2exe.org/index.cgi/TixSetup (als Bsp. wie man Libs hinzufügt)
Diesen könntest du auch schon auslagern. Oder wenigstens als Pythoncode kennzeichnen.boid hat geschrieben:Hier mein bisheriger Code (werde eventuell weitere bei irgendeinem Paste-Dienst einstellen):
Hier noch ein Beispiel zur Trennung von Daten, Logic und GUI:
http://paste.pocoo.org/show/24920/
Ich denke, man sieht gut, dass es geht, aber auch, das es nicht wirklich toll ist. Man kann auch die Logic von der Data Klasse erben lassen. Bei der GUI kommts drauf an, was du als erste Superclass angibst, damit die richtigen Methoden verfügbar sind.
@boid: Vorsicht, es kommt ein wenig Kritik.
`__del__()`-Methoden sind unnütz bis schädlich. Es wird nicht garantiert, dass die überhaupt jemals aufgerufen werden, und wenn sie vorhanden sind, kann es Situationen geben, in denen die Objekte nicht mehr vom Garbage-Collector freigegeben werden.
Mit dem `StringIO`-Modul käme man in `readHeader()` ohne temporäre Datei auf der Festplatte aus.
Statt der Tupel sollte man besser Listen verwenden. Das sieht nicht nur besser aus, als dass "anhängen" von einelementigen Tupeln, sondern ist auch performanter, weil nicht jedes mal die ganzen Daten kopiert werden müssen.
Anstelle von `struct`, könnte man mit dem `array`-Modul etwas komfortabler mehrere gleichartige Binärdaten lesen.
Nach einem kurzen Blick über den Quelltext scheint das `ConfigParser`-Objekt auserhalb von `Dat` nicht gebraucht zu werden. Der Quelltext wäre wohl kürzer und verständlicher wenn man die benötigten Daten dort einfach heraus holt und an Namen bindet, anstatt noch mehr hinein zu stecken.
`Dat.byteToFloat()` benutzt `self` nicht, wäre also eher eine Funktion.
`Dat.getHeader()` wird nicht verwendet. Wäre auch etwas überflüssig, weil man in Python normalerweise keine Getter und Setter schreibt, sondern direkt auf die Attribute zugreift. Falls man dann doch mal etwas komplexeres bei so einem Zugriff machen muss, gibt es Properties (`property()`).
In `Dat2CSV` werden wieder Tupel als Listen missbraucht.
`addDatFile()` ist reichlich kompliziert. Es gibt `os.path.split()` um Pfadnamen und Dateinamen voneinander zu trennen. Und alles was in `currentAllData` in einem Tupel zusammen gefasst wird, ist im Grunde redundant, weil die Daten alle im `Dat`-Objekt stecken. Dort könnte man sie auch einfach als Attribute zur Verfügung stellen. Womit die `addDatFile()` eigentlich zu einem ``self.dats.append(Dat(f))`` zusammen schrumpfen könnte. Die maximale Länge würde ich hier noch nicht ermitteln.
`convAddFiles()` und `convFile()` sind mit der Inederei zu komplex. Bitte wo möglich umschreiben, so dass direkt über die Elemente iteriert wird. Ausserdem habe ich das Gefühl, dass man die zu einer Methode zusammen fassen kann. Das `csv`-Modul bringt sicher auch etwas Übersichtlichkeit in die Sache.
In `Menu.__init__()` sind ein paar überflüssige Semikolons.
Insgesamt ist das `Menu` keine Klasse (wert). Wahrscheinlich käme man auch ganz gut ohne `Dat2CSV`-Klasse aus, was ja eher ein Funktionsname ist.
Und wie immer der Hinweis auf den Style Guide.
`__del__()`-Methoden sind unnütz bis schädlich. Es wird nicht garantiert, dass die überhaupt jemals aufgerufen werden, und wenn sie vorhanden sind, kann es Situationen geben, in denen die Objekte nicht mehr vom Garbage-Collector freigegeben werden.
Mit dem `StringIO`-Modul käme man in `readHeader()` ohne temporäre Datei auf der Festplatte aus.
Statt der Tupel sollte man besser Listen verwenden. Das sieht nicht nur besser aus, als dass "anhängen" von einelementigen Tupeln, sondern ist auch performanter, weil nicht jedes mal die ganzen Daten kopiert werden müssen.
Anstelle von `struct`, könnte man mit dem `array`-Modul etwas komfortabler mehrere gleichartige Binärdaten lesen.
Nach einem kurzen Blick über den Quelltext scheint das `ConfigParser`-Objekt auserhalb von `Dat` nicht gebraucht zu werden. Der Quelltext wäre wohl kürzer und verständlicher wenn man die benötigten Daten dort einfach heraus holt und an Namen bindet, anstatt noch mehr hinein zu stecken.
`Dat.byteToFloat()` benutzt `self` nicht, wäre also eher eine Funktion.
`Dat.getHeader()` wird nicht verwendet. Wäre auch etwas überflüssig, weil man in Python normalerweise keine Getter und Setter schreibt, sondern direkt auf die Attribute zugreift. Falls man dann doch mal etwas komplexeres bei so einem Zugriff machen muss, gibt es Properties (`property()`).
In `Dat2CSV` werden wieder Tupel als Listen missbraucht.
`addDatFile()` ist reichlich kompliziert. Es gibt `os.path.split()` um Pfadnamen und Dateinamen voneinander zu trennen. Und alles was in `currentAllData` in einem Tupel zusammen gefasst wird, ist im Grunde redundant, weil die Daten alle im `Dat`-Objekt stecken. Dort könnte man sie auch einfach als Attribute zur Verfügung stellen. Womit die `addDatFile()` eigentlich zu einem ``self.dats.append(Dat(f))`` zusammen schrumpfen könnte. Die maximale Länge würde ich hier noch nicht ermitteln.
`convAddFiles()` und `convFile()` sind mit der Inederei zu komplex. Bitte wo möglich umschreiben, so dass direkt über die Elemente iteriert wird. Ausserdem habe ich das Gefühl, dass man die zu einer Methode zusammen fassen kann. Das `csv`-Modul bringt sicher auch etwas Übersichtlichkeit in die Sache.
In `Menu.__init__()` sind ein paar überflüssige Semikolons.
Insgesamt ist das `Menu` keine Klasse (wert). Wahrscheinlich käme man auch ganz gut ohne `Dat2CSV`-Klasse aus, was ja eher ein Funktionsname ist.
Und wie immer der Hinweis auf den Style Guide.
ok, vielen Dank. Die letzten zwei Beiträge haben mir sehr geholfen.
Das GUI habe ich zwar gestern abend fertig gemacht auf eine Weise die mir persönlich nicht so gefällt, aber für die Größe des Projektes vermutlich angemessen ist. Nun muss ich daraus nur noch eine exe zimmern.
Ja, die Klassen enthalten tatsächlich ein paar ordentliche Designfehler. Tupel hatte ich extra gewählt, weil diese wohl performanter sein sollten als Listen. Wenn ich aber die Daten in zwei Klassen vorhalte und ständig ganze Tupel hin und her kopiere, brauche ich wirklich nicht über Performanz nachzudenken.
Die get/set Methoden habe ich gemacht, weil ich mittlerweile Funktionen wie readHeader in __readHeader umbenannt habe.
Da werde ich wohl nochmal nachbessern müssen. Manche Funktionen/Klassen wie array kannte ich bisher noch gar nicht.
Es wäre ja auch ein Wunder gewesen wenn ich an einem Tag eine neue Sprache perfekt beherrschen würde, zumal ich den OOP-Ansatz erst kürzlich intensiver nutze. Ich habe halt wirklich nur von PHP abstrahiert was ich nun ungefähr brauche und mal bei Python Openbook reingeschaut wie das ungefähr geht.
Das GUI habe ich zwar gestern abend fertig gemacht auf eine Weise die mir persönlich nicht so gefällt, aber für die Größe des Projektes vermutlich angemessen ist. Nun muss ich daraus nur noch eine exe zimmern.
Ja, die Klassen enthalten tatsächlich ein paar ordentliche Designfehler. Tupel hatte ich extra gewählt, weil diese wohl performanter sein sollten als Listen. Wenn ich aber die Daten in zwei Klassen vorhalte und ständig ganze Tupel hin und her kopiere, brauche ich wirklich nicht über Performanz nachzudenken.
Die get/set Methoden habe ich gemacht, weil ich mittlerweile Funktionen wie readHeader in __readHeader umbenannt habe.
Da werde ich wohl nochmal nachbessern müssen. Manche Funktionen/Klassen wie array kannte ich bisher noch gar nicht.
Es wäre ja auch ein Wunder gewesen wenn ich an einem Tag eine neue Sprache perfekt beherrschen würde, zumal ich den OOP-Ansatz erst kürzlich intensiver nutze. Ich habe halt wirklich nur von PHP abstrahiert was ich nun ungefähr brauche und mal bei Python Openbook reingeschaut wie das ungefähr geht.
@boid: Tupel sind im Grunde wie Listen, nur dass man sie nicht verändern kann. Es gibt einen kleinen Speicherplatzvorteil, weil Tupel, da nicht veränderbar, keinen Platz für spätere `append()`-Operationen "überbelegen", aber das ist hier ziemlich teuer erkauft, weil Du das `append()` ja recht häufig brauchst und es bei Tupeln halt von der Laufzeit echt ungünstig ist.
Auch bei einer `__readHeader()` braucht man keine extra `get`-Methode wenn die das Ergebnis an das Attribut `header` bindet. Wobei die zwei Unterstriche etwas übertrieben sind, wenn nicht gar schlechter Entwurf. Zwei führende Unterstriche sind dazu da, um Namenskollisionen in Unterklassen oder "Mixin"-Klassen zu vermeiden und nicht um so eine Art `private` wie in C++/C#/Java zu erzwingen. `private` ist in Python per Konvention *ein* führender Unterstrich. Das sagt anderen Programmierern, dass ist ein Implementierungsdetail, benutzen auf eigene Gefahr.
Meine Kritiken sind meistens kurz, knapp und technisch. Bitte nicht in den falschen Hals bekommen, ist wirklich nett gemeint und nicht als Angriff. Natürlich kann man nicht alles in der Standardbibliothek kennen, gerade als Einsteiger in die Sprache.
Auch bei einer `__readHeader()` braucht man keine extra `get`-Methode wenn die das Ergebnis an das Attribut `header` bindet. Wobei die zwei Unterstriche etwas übertrieben sind, wenn nicht gar schlechter Entwurf. Zwei führende Unterstriche sind dazu da, um Namenskollisionen in Unterklassen oder "Mixin"-Klassen zu vermeiden und nicht um so eine Art `private` wie in C++/C#/Java zu erzwingen. `private` ist in Python per Konvention *ein* führender Unterstrich. Das sagt anderen Programmierern, dass ist ein Implementierungsdetail, benutzen auf eigene Gefahr.
Meine Kritiken sind meistens kurz, knapp und technisch. Bitte nicht in den falschen Hals bekommen, ist wirklich nett gemeint und nicht als Angriff. Natürlich kann man nicht alles in der Standardbibliothek kennen, gerade als Einsteiger in die Sprache.
Mal ein völlig ungetesteter Anfang, wie man das mit weniger Klasse(n) und mehr und abstrakteren Funktionen machen kann: http://paste.pocoo.org/show/25093/
Ist vielleicht genauso unverständlich wie dreifach indirekter Indexzugriff in tief verschachtelten Schleifen, aber dafür kompakter.
Ist vielleicht genauso unverständlich wie dreifach indirekter Indexzugriff in tief verschachtelten Schleifen, aber dafür kompakter.
- Rebecca
- User
- Beiträge: 1662
- Registriert: Freitag 3. Februar 2006, 12:28
- Wohnort: DN, Heimat: HB
- Kontaktdaten:
Daraus solltest du dir eine Signatur machen.BlackJack hat geschrieben:Meine Kritiken sind meistens kurz, knapp und technisch. Bitte nicht in den falschen Hals bekommen, ist wirklich nett gemeint und nicht als Angriff.
Offizielles Python-Tutorial (Deutsche Version)
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei