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

``raw_input()`` ist ein Funktions*aufruf* der eine Zeichenkette zurückgibt. ``raw_input`` ist eine Funktion:

Code: Alles auswählen

In [32]: type(raw_input())
42
Out[32]: <type 'str'>

In [33]: type(raw_input)
Out[33]: <type 'builtin_function_or_method'>
Wie man an dem Beispiel sieht, ist es nicht ganz egal was man übergibt, weil dadurch der Zeitpunkt bestimmt wird, wann die Eingabefunktion ausgeführt wird, ob nun vor dem Aufruf von `test()` oder erst in `test()`. Wenn die Funktion vor dem Aufruf nicht irgendetwas macht oder die Eingabefunktion mehrfach aufruft, ist die Funktionsübergabe statt einer Zeichenkette unnötig komplex.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:``raw_input()`` ist ein Funktions*aufruf* der eine Zeichenkette zurückgibt. ``raw_input`` ist eine Funktion:
Ja, eigentlich ganz logisch, es hat geklingelt.

Code: Alles auswählen

In [32]: type(raw_input())
42
Out[32]: <type 'str'>

In [33]: type(raw_input)
Out[33]: <type 'builtin_function_or_method'>
Wie man an dem Beispiel sieht, ist es nicht ganz egal was man übergibt, weil dadurch der Zeitpunkt bestimmt wird, wann die Eingabefunktion ausgeführt wird, ob nun vor dem Aufruf von `test()` oder erst in `test()`.
Warum hast es mir denn nicht gleich so erklärt, dann müsste ich mir nicht so begriffsstutzig vorkommen, loool
Wenn die Funktion vor dem Aufruf nicht irgendetwas macht oder die Eingabefunktion mehrfach aufruft, ist die Funktionsübergabe statt einer Zeichenkette unnötig komplex.
Dieser Teil ist jetzt in Bezug auf mein Beispiel noch nicht ganz klar. Im vorigen Beispiel dann doch besser:

Code: Alles auswählen

eingabe = wert_funktionsaufruf
 #... und daher dann z. Bsp bei Entry

....command = lambda:entry.get()....
LG

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

...ich probiers mal mit einer Antwort von mir selbst, ggg.

Wenn ich mir die konkrete Methode ansehe, dann werde ich diese wohl so ändern müssen, dass eine Funktion und nicht die Zeichenkette eines Funktionsaufruf übergeben wird, oder?

Code: Alles auswählen

    def edit(self, number):
        data = self.entries[int(number) - 1]
        for key in self.keys:
            if data[key]:
                entry = raw_input("%s %s neu ? --> " % (key.capitalize(),
                                                          data[key]))
            else:
                entry = raw_input("%s hinzufügen ? --> " % key.capitalize())
            if entry:
                data[key] = entry

Die Methode ist noch überhaupt nicht für die neuen Ansprüche angepasst.
Ein weiteres Problem es unabhängig von dem Interface zu machen ist auch das hier:

Code: Alles auswählen

"%s %s neu ? --> " % (key.capitalize(),
                                                          data[key])
Es bleibt wohl mehr zu klären, als die Frage: Übergabe einer Funktion oder einer Zeichenkette.

LG

r_r
BlackJack

Okay, ich habe im Laufe der Woche mal einen "literate programming"-Versuch an dieser Aufgabe durchgeführt. Herausgekommen ist dieser Quelltext mit ca. 78% Kommentarzeilen:

http://www.marc.rintsch.de/simpledb/simpledb.py

Etwas schöner liest sich vielleicht die HTML-Version:

http://www.marc.rintsch.de/simpledb/simpledb.html

Oder ein gedrucktes PDF (mit Syntaxhighlighting der Quelltextteile):

http://www.marc.rintsch.de/simpledb/simpledb.pdf

Der Quell-Quelltext ist hier:

http://www.marc.rintsch.de/simpledb/simpledb.py.txt

:-D

Dabei bin ich im Grunde so vorgegangen wie ich das gaaanz früher im Informatikunterricht in der Schule mal gelernt habe: Das Problem in immer kleinere Unterprobleme aufteilen, die sich leicht und übersichtlich mit kleinen Funktionen/Prozeduren lösen lassen, und diese Teillösungen dann zu einer Gesamtlösung zusammensetzen. Damals mit Pascal und das Projekt war, oh Wunder, eine Adressdatenbank. :-)
Grossmeister_C
User
Beiträge: 36
Registriert: Montag 26. Februar 2007, 15:53

Hast Dir ja richtig Arbeit mit der Dokumentation gemacht.

Respekt, so muß das :)
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
Antworten