Was geht noch einfacher?

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.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

@BlackJack

Also ich bin jetzt einmal durch.
Natürlich ist das schöner Code, da kann ich mir ne Menge ansehen und lernen.

Andererseits sehe ich nicht was der Code kann, was meine OOPlösung nicht kann. Oder auch die imperative ohne global.


Ohne Zweifel ist deine richtiger, besser, aber wenn ich so korrekt sein will in Bezug auf die IDs z. Bsp. dann sprech ich doch gleich eine Datenbank an.
An dieser Stelle kann man sehen, dass diese Überlegung bzw. Entscheidung ihre Berechtigung hätte:

Code: Alles auswählen

>>> brain = (1, ('Brain', 'Weltherrscher'))
>>> records = [erik, brain]
>>> records
[(0, ('Erik', 'Wikinger')), (1, ('Brain', 'Weltherrscher'))]
In Englisch würde ich es zunächst auch nicht machen, wenn dann einen deutschen Quelltext übersetzen.

Mediendidaktisch, -pädagogisch ist es unter bestimmten Aspekten 1a.
Und natürlich möchte ich mich auch bedanken, dass du dir soviel angetan hast.

Damit werde ich mich sicherlich noch öfter auseinandersetzen.

LG

rolgal_reloaded
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

Hallo rolgal,

hier mal ein versuch mit einer Gui.

Die Gui ist mit SpecTcl erstellt also lass dich nicht von 300 Zeilen Guicode stören.
http://www.ubuntuusers.de/paste/11311/

MultiListBox: http://www.ubuntuusers.de/paste/11313/

Es ist echt nur ein versuch und es muss weiter ausgebaut werden.
Gruss
pyStyler
Zuletzt geändert von pyStyler am Freitag 1. Juni 2007, 22:24, insgesamt 1-mal geändert.
BlackJack

Es ging ja nicht (nur) darum was der Code kann, sondern wie er strukturiert ist. Die Funktionen selbst sind für Anfänger wahrscheinlich zu kryptisch oder knapp geschrieben und natürlich kann man auch deutsche Bezeichner verwenden.

Ich denke das Aufteilen in kleine übersichtliche und einzeln test- und "ausprobierbare" Einheiten, ob das nun Funktionen oder Methoden sind, ist eine wichtige Sache. Nur so lassen sich grössere Programme schreiben, ohne dass man die Übersicht verliert. Und so eine kleine Datenbank ist im Grunde schon ein mittelgrosses Projekt.

Was der Code auf jeden Fall mehr "kann", ist die Trennung von Programmlogik und GUI.

Wie in den Kommentaren/der Doku zu dem Quelltext schon steht, ist Python ohne Klassen eigentlich zu mehr oder weniger funktionaler Programmierung verdammt. Das Pascal-Programm, was wir damals in der Schule entwickelt hatten, benutzte natürlich ``RECORD``\s und war damit doch etwas lesbarer.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

pyStyler hat geschrieben:Hallo rolgal,

hier mal ein versuch mit einer Gui.

Die Gui ist mit SpecTcl erstellt also lass dich nicht von 300 Zeilen Guicode stören.
http://www.ubuntuusers.de/paste/11311/

MultiListBox: http://www.ubuntuusers.de/paste/11313/

Es ist echt nur ein versuch und es muss weiter ausgebaut werden.
Gruss
pyStyler
Hallo pyStyler,

ganz kurz, meine Tocher macht heute mächtig Zoff - class NoSleepTonight, ggg.
Ob dafür eine Klasse gerechtfertigt ist oder nicht, muss ich wohl vor allem mit ihr diskutieren, loool

Sieht sehr interessant aus, was ich ad hoc nicht verstehe ist die Klasse Main. Die Attribute (self.atrs) sollten auf keinen Fall konstant sein, müssten ja auch leicht von DataBook zu bekommen sein.....

Alles check ich heute nicht mehr mit dem Geplärr im Ohr:-))

Bis bald,

lG

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

.....bis daher stimme ich allem zu!
Was der Code auf jeden Fall mehr "kann", ist die Trennung von Programmlogik und GUI.
Ahhhh,....und ich glaube durch einen zweiten Blick auf den Code zu wissen warum, also stimme ich eigentlich weiter zu:-)
Wenn doch nicht, frage ich verlässlich nach, ggg.

LG

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

@pyStyler

Die Optik ist ja echt schon sehr gut, kommt gut rüber, jetzt werde ich mal sehen, ob ich etwas mehr Durchblick bekomme.

LG

r_r
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

@blackjack:

Ich habe das heute auch mal wieder angesehen:


http://www.ubuntuusers.de/paste/11081/


Dabei habe ich nur main() etwas angepasst:

Code: Alles auswählen

def main():
    path = "C:/Dokumente und Einstellungen/rolgal/Eigene Dateien/Unterricht/PI Tirol/Python/adressbuch.bin"
    try:
        addresses = Addresses.load(path)
    except IOError:
        addresses = Addresses(['name', 'vorname', 'straße', 'nummer', 'plz',
                               'ort'])
    
    print addresses
    addresses.enter()
    keyword = raw_input('Suchbegriff: ')
    print addresses.search(keyword)
    addresses.save(path)


if __name__ == "__main__": 
    main()
Ich würde sagen da knallt es, oder?

Code: Alles auswählen

>>> 
[{'nummer': '', 'name': 'Huber', 'ort': '', 'stra\xdfe': 'Daxgasse', 'plz': '', 'vorname': 'Gerhard'}]

Traceback (most recent call last):
  File "C:/Dokumente und Einstellungen/rolgal/Eigene Dateien/Programmierung/Forum/oop_databook_bj.py", line 80, in <module>
    main()
  File "C:/Dokumente und Einstellungen/rolgal/Eigene Dateien/Programmierung/Forum/oop_databook_bj.py", line 73, in main
    addresses.enter()
AttributeError: 'list' object has no attribute 'enter'
>>> 

Das klappt doch mit load zur Instanzierung so nicht, oder?

LG

rolgal_reloaded
BlackJack

Die Datei scheint eine Liste und kein `Addresses`-Objekt zu enthalten. Mit der `Adresses.save()`-Methode ist die Datei also wohl nicht erstellt worden.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:Die Datei scheint eine Liste und kein `Addresses`-Objekt zu enthalten. Mit der `Adresses.save()`-Methode ist die Datei also wohl nicht erstellt worden.
Hätte mich doch gewundert, wenn der Fehler nicht bei mir gelegen wäre :D

Du speicherst ja auch self!

Das muss es sein, werde ich ausprobieren.


LG

r_r
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Ich habe jetzt die Klasse, auch als Konsequenz deines Megabeitrages so umgeschrieben, dass sie unabhängig vom UI ist.

Dabei kam ich wenig überraschend auf ähnlichen Code wie bei deinem Bsp. damals.

Allerdings sind die Edit, Enter draussen.

Momentan bastel ich eine TUI_DataBook Klasse. Da habe ich noch einige Kleinigkeiten zu klären.

Hier mal die aktuelle Version:

http://www.ubuntuusers.de/paste/11379/


@pystyler:

Das wird wohl auch für deinen Bemühungen eine GUI zu schreiben die bessere Grundlage sein.

Für den Unterricht könnte ich wohl aus bestimmten Gründen zunächst dabei bleiben, der Aufwand die SchülerInnen auf obiges Beispiel vorzubereiten erscheint mir jetzt noch wesentlich größer, wir werden ja sehen....:

http://www.ubuntuusers.de/paste/11232/


LG

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Hier mal der Versuch ein TUI mit einer Klasse zu machen:
Gesamter Code inkl. DataBook.


http://www.ubuntuusers.de/paste/11393/


Besonders stört mich selbst noch, dass folgende Methode der Klasse TUI_DataBook, die Anzahl der Einträge überprüft. Das scheint mir nicht so schön.
Mir ist aber noch keine wirkliche gelungene Alternative eingefallen.
Soll ich vielleicht eine Error- und Sucessmessage in DataBook definieren und die von über return an die untenstehende Methode zurückgeben?

Code: Alles auswählen

    def enter(self):
        number = 0
        values = []
        for key in self.keys:
            entry = raw_input("%s: " % key.capitalize())
            if entry:
                values.append(entry)
                number += 1
            else:
                values.append("")
                
        if number >= self.instance.min_entries:
            self.instance.add_entry(values)
            print "Entry added"
        else:
            print "You have to make at least %s entries" % self.instance.min_entries


Für sonstige Hinweise, Kommentare jeder Art bin ich wie immer auch dankbar.


LG

rolgal_reloaded
BlackJack

Das man so etwas mit einer Ausnahme, zum Beispiel `ValueError` im `DataBook` beantwortet, ist wahrscheinlich für Deine Zielgruppe angeblich wieder zu kompliziert. ;-)
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:Das man so etwas mit einer Ausnahme, zum Beispiel `ValueError` im `DataBook` beantwortet, ist wahrscheinlich für Deine Zielgruppe angeblich wieder zu kompliziert. ;-)
Mach dich ruhig lustig,.....
Ausserdem solltest du gelesen haben, dass ich zur Zeit dieses Beispiel noch nicht für meine Zielgruppe sehe, das kann sich aber auch mit der Zeit, die gute Ideen zur didaktischen Aufarbeitung bringt ändern.

Zum Inhalt:
Wieso mit einem ValueError? Meinst du mit raise ValueError - ?

Code: Alles auswählen

    def add_entry(self, values):
        if sum(1 for value in values if value) >= self.min_entries:
            data = {}
            for i, key in enumerate(self.keys):
                data[key] = values[i]
            self.entries.append(data)
        else:
            raise ValueError("Minimum Entries %s" % self.min_entries)
Dann ist das Programm beendet, irgendwie fände ich es hübscher wenn das Programm weiterläuft, oder verstößt das wieder gegen die zehn Gebote des guten Code :wink:

Oder ich habe es noch nicht verstanden, was du meinst, guuut möglich, kennen wir ja:-))

LG

rolgal_reloaded
BlackJack

`ValueError` weil das IMHO von den Standard-Ausnahmen am besten passt -- der Wert des Arguments entspricht nicht den Vorgaben.

Damit sich das Programm nicht beendet, sollte man die Ausnahme natürlich an der entsprechenden Stelle im Programm mit ``try``/``except`` behandeln. Und den Benutzer darüber informieren und ihm am besten den Eintrag nochmal zum bearbeiten vor die Nase setzen.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:`ValueError` weil das IMHO von den Standard-Ausnahmen am besten passt -- der Wert des Arguments entspricht nicht den Vorgaben.

Damit sich das Programm nicht beendet, sollte man die Ausnahme natürlich an der entsprechenden Stelle im Programm mit ``try``/``except`` behandeln. Und den Benutzer darüber informieren und ihm am besten den Eintrag nochmal zum bearbeiten vor die Nase setzen.
Sowas habe ich mir eigentlich gedacht, heisst im Idealfall vorgestellt, aber ich habe schon ein except, das mit return eine Meldung zurückgibt, die eigentlich aber nicht zu sehen ist. Irgendwas habe ich im Detail noch nicht geschnallt.

Vielleicht check ich es ja noch.

Das mit dem ValueError leuchtet ein.

Danke,

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

...also mit try....except müsste es so aussehen, oder?

Code: Alles auswählen

    def add_entry(self, values):
        try:
            if sum(1 for value in values if value) >= self.min_entries:
                data = {}
                for i, key in enumerate(self.keys):
                    data[key] = values[i]
                self.entries.append(data)
                return "Entry added!"
            else: raise ValueError
        except ValueError:
            return "Minimum Entries %s" % self.min_entries
Aber der Aufruf dieser Methode muss dann an eine Variable gebunden sein und deren Inhalt muss dann mit print ausgegeben werden.
Da gibts wohl keine andere Möglichkeit?

LG

r_r
BlackJack

Das macht doch gar keinen Sinn die Ausnahme dort zu behandeln. Dann hätte man doch gleich die ``return``\s in die ``if``- und ``else``-Zweig unterbringen können. Die Ausnahme ist ein Signal für den Aufrufer und im Gegensatz zu einem einfachen Rückgabewert für Erfolg oder Misserfolg nicht zwangsläufig für den *direkten* Aufrufer, sondern für irgendeinen in der Aufruferkette, der sich verantwortlich fühlt die Ausnahme zu behandeln.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:..... Die Ausnahme ist ein Signal für den Aufrufer und im Gegensatz zu einem einfachen Rückgabewert für Erfolg oder Misserfolg nicht zwangsläufig für den *direkten* Aufrufer, sondern für irgendeinen in der Aufruferkette, der sich verantwortlich fühlt die Ausnahme zu behandeln.
:?: - liegt wohl an Wochentag und Uhrzeit

Wenn dies nicht der richtige Ort ist, dann bleiben nur 2 andere Möglichkeiten.
TUI_DataBook, oder das Hauptprogramm. Ersteres finde ich nicht sinnvoll.

Also?

Code: Alles auswählen

        elif choice == "i":
            values = app.enter()
            try:
                if sum(1 for value in values if value) >= adressbuch.min_entries:
                    adressbuch.add_entry(values)
                else:
                    raise ValueError
            except ValueError:
                print "Minimum Entries must be %s" % adressbuch.min_entries
LG

r_r
BlackJack

Es liegt wohl an der Uhrzeit. Es macht keinen Sinn die Ausnahme an dem Ort zu behandeln wo sie ausgelöst wird! Das sollte man doch eigentlich *sehen*, dass das so einfach nur unnötiger Schreibaufwand ist!

Da die minimale Anzahl zur `DataBook`-Klasse gehört, sollte sie auch dort überprüft werden. Und wenn die Bedingung nicht erfüllt ist, dann wird dort die Ausnahme ausgelöst.

Wenn Du ``int('fortytwo')`` ausführst, dann wird innerhalb der `int()`-Funktion geprüft, ob es sich bei der Zeichenkette um eine Zahl handelt und wenn nicht, wird in der Funktion ein `ValueError` ausgelöst. Und der wird nicht da drin wieder behandelt und in einen Rückgabewert umgewandelt. Dann würde man "aussen" ja gar nichts davon mitbekommen.

Die `add_entry()`-Methode kann dann also die Ausnahme auslösen, also muss man die *aussherhalb* der Methode irgendwo auf dem "Weg nach draussen" abfangen, wenn man nicht möchte, dass das Programm beendet wird.

Code: Alles auswählen

        elif choice == "i":
            values = app.enter()
            try:
                adressbuch.add_entry(values)
            except ValueError, error:
                print error
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

@BlackJack

Die Sache mit Fehler-, Ausnahmenbehandlung muss ich mir noch intensiver anschauen.

Für den Fall hier dürfte jetzt alles klar sein:

Code: Alles auswählen

    def add_entry(self, values):
        if sum(1 for value in values if value) >= self.min_entries:
            data = {}
            for i, key in enumerate(self.keys):
                data[key] = values[i]
            self.entries.append(data)
        else:
            raise ValueError("Minimum Entries must be %s" % self.min_entries)
Also wie schon gehabt und im Hauptprogramm die Behandlung wie von dir gezeigt.

@edit:
Dann muss ich das mit der Methode load natürlich auch entsprechend ändern.



Vielen Dank nochmal,

rolgal_reloaded
Antworten