Seite 1 von 6

Verfasst: Samstag 26. Mai 2007, 16:57
von rolgal_reloaded
@alle

Danke nochmal für die interessanten Antworten.
Rein zufällig habe ich sie gesehen, ich bekomme nämlich die halbe Zeit keine Mail, dass ich eine Antwort erhalten habe.

LG

rolgal_reloaded

Verfasst: Samstag 26. Mai 2007, 17:02
von rolgal_reloaded
BlackJack hat geschrieben:Nochmal kurz zum Beispiel oben: Beim Speichern werden die Argumente `pfad` und `adressbuch` nicht verwendet. In `suchen()` wird `treffer` unnötigerweise an das Objekt gebunden.

`anzeigen()` zeigt nichts an, sondern liefert eine Zeichenkette. Könnte man also als `__str__()` implementieren und `Adressbuch`-Objekte dann einfach mit ``print`` ausgeben.

Hier das gewünschte Beispiel: http://www.ubuntuusers.de/paste/11081/
Das wollte ich ursprünglich auch, hat nicht geklappt, inzwischen glaube ich auf Grund deines Beispieles gesehen zu haben warum.

LG

rolgal_reloaded

Verfasst: Samstag 26. Mai 2007, 17:10
von rolgal_reloaded
schlangenbeschwörer hat geschrieben:Da es hier ja um Codeverbesserung geht, und dieses Programm gut dafür geeignet ist, da es kurz aber dennoch sinnvoll ist, hätte ich da mal Frage: Man soll ja die Programmierung und die Graphik möglichst komplett auseinanderhalten. Die ´print´ und ´raw_input´-Sachen sind ja eigentlich nur ein GUI-Ersatz, müssten also doch eigentlich auch von der Adressbuch-Klasse getrennt werden, oder? Mich würde das mal interessieren, wie das wirklich sauber geht, da ich, wenn ich Programme mit Gui schreibe, zwar das GUI in eine eigene Klasse packe, die "Inhalts-Klasse" aber genau auf diese abstimme, sodass es fast keine Sinn mehr macht.
Dieses Programm wär doch jetzt mal gut, um es als Grundlage für das ultimative Beispielprogramm für guten Progammierstil zu verbessern, denn es gibt zwar Tutorials für den Inhalt, aber für sowas doch recht selten (habs zumindest noch nicht gesehen).
Was haltet ihr davon, die Klassenversion oben so zu verbessern, dass ein paar Leute sie verwenden können, und, ohne sie zu verändern, ein GUI in dem entsprechenden Toolkit zu schreiben? Ich hab schon überlegt, wie ich das mit Tkinter machen würde, aber da müsste ich die komplette Klasse umbasteln, und die wär dann wieder so, das einer, der ein wx-Beispiel damit machen will, es wieder ändern muss....Zudem käme hierbei noch der Toolkit-Vergleich zustande, da das Programm ja recht gewöhnlich ist, für ein Programm, wofür man ein GUI schreibt.
Ich fänd das echt lehrreich.

Gruß, jj
Gute Idee, bei mir sind da auf Grund der Weiterentwicklung der Lösung 1 - alles global noch viele Dinge drin, die natürlich in weiterer Folge rausgehören. Ich finde es sehr fein, nicht nur für mich, sondern für jeden im Lernprozess, viele Abstufungen bzw. Weiterentwicklungen zu sehen und an ihnen im Detail den Mehrwert zu erkennen.

LG

rolgal_reloaded

Verfasst: Samstag 26. Mai 2007, 18:14
von Leonidas
schlangenbeschwörer hat geschrieben:Da es hier ja um Codeverbesserung geht, und dieses Programm gut dafür geeignet ist, da es kurz aber dennoch sinnvoll ist, hätte ich da mal Frage: Man soll ja die Programmierung und die Graphik möglichst komplett auseinanderhalten. Die ´print´ und ´raw_input´-Sachen sind ja eigentlich nur ein GUI-Ersatz, müssten also doch eigentlich auch von der Adressbuch-Klasse getrennt werden, oder?
Richtig. Die Klasse ist eine API, auf die der Nutzer des Programms keinen Zugriff haben sollte. Die Klasse sollte eine Aufgabe haben und nur eine. Die meisten Klassen sind dazu Daten strukturiert zu kapseln und zu verarbeiten. Die Ausgabe übernimmt ein anderer Code.
schlangenbeschwörer hat geschrieben:Mich würde das mal interessieren, wie das wirklich sauber geht, da ich, wenn ich Programme mit Gui schreibe, zwar das GUI in eine eigene Klasse packe, die "Inhalts-Klasse" aber genau auf diese abstimme, sodass es fast keine Sinn mehr macht.
Dann solltest du die GUI und die Klasse nicht gleichzeitig machen, weil sowas dann zur zu engen Verzahnung zwischen Inhalt (=Daten) und Darstellung (=GUI) kommt, die zu schwer verständlichen Programmen führt.
Eine solche Trennung hat beispielsweise Dookies 7-Segmente-Programm, welches verschiedene UIs hat (auch denn die UI-unabhängige Klasse Properties teilweise sinnlos nutzt. What's On Air ist ebenso UI-unabhängig:
es hat ein Kommandozeileninterface aber auch ein PyGTK-Interface. Eine Zeitlang gab es auch eine Tkinter-UI (die jemand anders geschrieben hat), aber da sie keiner maintaint hat, wurde die rausgenommen.
schlangenbeschwörer hat geschrieben:Dieses Programm wär doch jetzt mal gut, um es als Grundlage für das ultimative Beispielprogramm für guten Progammierstil zu verbessern, denn es gibt zwar Tutorials für den Inhalt, aber für sowas doch recht selten (habs zumindest noch nicht gesehen).
Wäre ok. Aber ich wäre dafür die benötigten Spezifikationen aufzustellen und diese zu implementieren - das geht sicherlich schneller, als rolgal_reloadeds Programm umzuschreiben, denke ich. Zumindest finde ich, dass das schneller geht. Wir können ja auch erstmal Unittests schreiben und dann das Programm implementieren, als Test-first-Ansatz, der von selbst schon eine Art Spezifikation ist.
schlangenbeschwörer hat geschrieben:Ich fänd das echt lehrreich.
Können wir machen. Während man aber eine GUI schreibt, merkt man eben manchmal, dass die API an einigen stellen schlecht ist - dann muss dort nachgebessert werden. Ich glaube aber, dass man sowas merkt, wenn man Unittests schreibt.

Verfasst: Samstag 26. Mai 2007, 19:50
von rolgal_reloaded
BlackJack hat geschrieben:
Hier das gewünschte Beispiel: http://www.ubuntuusers.de/paste/11081/
Vielleicht habe ich mir jetzt zu wenig Zeit gelassen,....wie auch immer, was bringt es die ganzen Methoden wie __len__ zu implementieren. __str__ ist mir klar.
Ich mein die Auswirkung ist schon klar: adressbuch.len(), aber der tatsächliche Nutzen bleibt mir noch verborgen.

Irgendwas seh und/oder check ich da jetzt nicht :oops:

LG

rolgal_reloaded

Verfasst: Samstag 26. Mai 2007, 20:02
von Leonidas
rolgal_reloaded hat geschrieben:was bringt es die ganzen Methoden wie __len__ zu implementieren.
Wenn du ``__len__`` implementiest, kannst du ``len()`` auf eine Instanz deiner Klasse anwenden und bekommst somit ihre "Länge", d.h. die Anzahl der in ihr gespeicherten Adressen. Das ist insofern praktisch, dass der Anwender der Klasse nicht wissen muss ob man die anzahl der Einträge mit ``instanz.lenght()`` oder ``instanz.get_number_of_items()`` oder ``instanz.getItemNumber()`` aufrufen muss. Er kann einfach ``len(instanz)`` nutzen und das gibt ihm dann die Anzahl aus. Es ist eine Art, die API aller Klassen einheitlich zu halten.

Verfasst: Samstag 26. Mai 2007, 20:14
von rolgal_reloaded
Leonidas hat geschrieben:
rolgal_reloaded hat geschrieben:was bringt es die ganzen Methoden wie __len__ zu implementieren.
Wenn du ``__len__`` implementiest, kannst du ``len()`` auf eine Instanz deiner Klasse anwenden und bekommst somit ihre "Länge", d.h. die Anzahl der in ihr gespeicherten Adressen. Das ist insofern praktisch, dass der Anwender der Klasse nicht wissen muss ob man die anzahl der Einträge mit ``instanz.lenght()`` oder ``instanz.get_number_of_items()`` oder ``instanz.getItemNumber()`` aufrufen muss. Er kann einfach ``len(instanz)`` nutzen und das gibt ihm dann die Anzahl aus. Es ist eine Art, die API aller Klassen einheitlich zu halten.
Das heisst, es geht darum jmd. der mit dieser Klasse etwas programmiert Methoden anzubieten, wie er sie auch von der Klasse List kennt?
Immerhin ist es ja eine Liste.

LG

rolgal_reloaded

Verfasst: Sonntag 27. Mai 2007, 10:43
von schlangenbeschwörer
Wie intensiv man diese magischen Methoden für eine Klasse überläd hängt natürlich davon ab, es für eine Klasse ist und wer damit arbeitet. Wenn sie eh nur von einem Programm verwendet wird, in dem man diese Funktion nicht immer braucht, sind sie eher überflüssig, aber wenn man eine Klasse schreibt, die auch von anderen als Grundlage für verschiedenen Programme genutzt wird, hilft es schon. Zum einen ist es kürzer und zum anderen muss man den fremden Code nicht so verinnerlichen.

@Leonidas: Ehmm...wie schreibt man Unittests?
Und wie trennt man dann Daten und Darstellung, wenn man nicht nur auf die Klasse zugreift, sondern diese auch selbstständig bei bestimmten Gegebenheiten etwas darstellen will? Der __init__ entsprechende Methoden übergeben, die bestimmte Vorraussetzungen erfüllen? Also so, wie man stdout eine Instanz einer Klasse mit einer write-Methode übergibt? Oder alles mit return regeln, sodass man überprüfen muss, was zurückgegeben wird? Das denke ich, ist wohl besser, aber oft schwer zu machen...

Gruß, jj

Verfasst: Sonntag 27. Mai 2007, 13:39
von rolgal_reloaded
Hallo nochmal,

also ich versuche immer gezeigtes einfließen zu lassen und dabei eigenes nicht gleich komplett zu verwerfen.
Weil einfach etwas zu 100% übernehmen = abschreiben nicht so das Ultimative ist, denke ich mal.

Ich habe jetzt bez. anzeigen() mal folgende Lösung probiert. Ein Mix BlackJack - Leonidas - rolgal_reloaded.....im Ernst gibts da grob was einzuwenden?

Code: Alles auswählen

    def __str__(self, ergebnis = None):
        if not ergebnis:
            ergebnis = self.eintraege
        ausgabe = ""
        for i, adresse in enumerate(ergebnis):
            ausgabe += str(i + 1) 
            for key in self.keys:
                ausgabe += " "
                ausgabe += adresse[key]
            ausgabe += "\n"
        return ausgabe

    def anzeigen(self):
        return self

    def suchen(self, suchbegriff):
        self.treffer = []
        for adresse in self.eintraege:
            if suchbegriff in adresse.itervalues():
                self.treffer.append(adresse)
        if self.treffer:
            return self.__str__(self.treffer)
        else:
            return 'Leider keinen Eintrag gefunden'

Jetzt kann man auf die Instanz print anwenden und __str__ innerhalb der Klasse wiederverwenden.
anzeigen() kann man wohl auch weglassen.

LG

rolgal_reloaded

Verfasst: Sonntag 27. Mai 2007, 14:18
von BlackJack
Warum `self.treffer` statt nur `treffer`?

Verfasst: Sonntag 27. Mai 2007, 14:32
von rolgal_reloaded
BlackJack hat geschrieben:Warum `self.treffer` statt nur `treffer`?
Das ist noch ein Überbleibsel, in irgendeinem Versuch habe ich es als Instanzattribut gebraucht , das gehört jetzt natürlich weg , danke für den Hinweis!

LG

rolgal_reloaded

Verfasst: Sonntag 27. Mai 2007, 16:25
von schlangenbeschwörer
Könntest du vlt. nochmal deinen aktuellen Code im Ganzen posten, möglichst schon Daten und Darstellung getrennt? Dann würd ich mal sehn, was man noch ändern bzw. anpassen muss und versuchen, ein einfaches GUI zu schreiben, aber deine Klasse so zu lassen, das andere hier GUIs mit anderen Toolkits schreiben können.

Verfasst: Sonntag 27. Mai 2007, 16:55
von rolgal_reloaded
schlangenbeschwörer hat geschrieben:Könntest du vlt. nochmal deinen aktuellen Code im Ganzen posten, möglichst schon Daten und Darstellung getrennt? Dann würd ich mal sehn, was man noch ändern bzw. anpassen muss und versuchen, ein einfaches GUI zu schreiben, aber deine Klasse so zu lassen, das andere hier GUIs mit anderen Toolkits schreiben können.
Meinst du mich :?:
Nehme ich an wegen - nochmal deinen aktuellen usw.

Oder eine Version von Leonidas - nehme ich an, weil du mit ihm ein Projekt besprochen hast.

LG

rolgal_reloaded

Wie ist das eigentlich....

Verfasst: Sonntag 27. Mai 2007, 17:08
von rolgal_reloaded
mit folgendem:

Code: Alles auswählen

    def eintragen(self):
        adresse = {}
        anzahl = 0
        for key in self.keys:
            eintrag = raw_input("%s: " % key.capitalize())
            if eintrag:
                adresse[key] = eintrag
                anzahl += 1
            else:
                adresse[key] = ""

        if self.mindestanzahl:
            if anzahl < self.mindestanzahl:
                return "Es müssen mindestens\
 %s Einträge gemacht werden!" % self.mindestanzahl
            else:
                self.eintraege.append(adresse)
                return "Eintrag hinzugefügt!"
Ich habe hiermal die Printanweisungen rausgenommen.
Das bedeutet für den Aufruf:
eintrag = adressbuch.eintragen()
print eintrag

oder nur adressbuch.eintragen()

Dann wird die Rückgabe aber wohl zu einem anonymen Objekt oder?
Sollte man sowas irgendwie unterbinden, weil es schlechter Stil ist.
Oder ist es einfach dem Benutzer seine Sache wie er den Aufruf macht?

LG

rolgal_reloaded

Verfasst: Sonntag 27. Mai 2007, 17:20
von schlangenbeschwörer
rolgal_reloaded hat geschrieben: Meinst du mich :?:
:arrow: ja

Zu deiner letzten Frage: Es geht ja grade darum, das die Klasse nicth für den "Endverbraucher" sein soll, sondern für Leute wie mich grade, die die Klasse dann dem "Endverbraucher", der nix von Pyhton versteht bzw. verstehen muss, nutzbar machen. Du kannst auch eine Konsolenanwendung schreiben. Das machst du dann in einer neuen Klasse oder Funktion, wo du mit einer Instanz deiner Grundklasse arbeitest und die Eingaben in Methodenaufrufe umwandelst und umgekehrt die zurückgegebenen Werte entsprechend dem Benutzer ausgibst.

Verfasst: Sonntag 27. Mai 2007, 17:33
von rolgal_reloaded
schlangenbeschwörer hat geschrieben:
rolgal_reloaded hat geschrieben: Meinst du mich :?:
:arrow: ja

Zu deiner letzten Frage: Es geht ja grade darum, das die Klasse nicth für den "Endverbraucher" sein soll, sondern für Leute wie mich grade, die die Klasse dann dem "Endverbraucher", der nix von Pyhton versteht bzw. verstehen muss, nutzbar machen. Du kannst auch eine Konsolenanwendung schreiben. Das machst du dann in einer neuen Klasse oder Funktion, wo du mit einer Instanz deiner Grundklasse arbeitest und die Eingaben in Methodenaufrufe umwandelst und umgekehrt die zurückgegebenen Werte entsprechend dem Benutzer ausgibst.
Ich versteh schon was du meinst, ob meine Frage damit beantwortet ist weiss ich dennoch nicht:-)

Der Code ist im ganzen vielleicht etwas lang, wie und wo kann ich das jetzt außerhalb des Forums posten?

@edit:

Ich habs wieder denke ich:

http://paste.pocoo.org/show/1527/

LG

r_r

Verfasst: Sonntag 27. Mai 2007, 17:48
von Leonidas
schlangenbeschwörer hat geschrieben:@Leonidas: Ehmm...wie schreibt man Unittests?
Dazu gibts ein ganzes Kapitel in "Dive into Python", danach komt gleich das Kapitel zu Test-First-Programming. Inzwischen müsste man aber überlegen, ob man das Modul ``unittest`` noch verwenden will oder sollte oder ob man nicht besser ``doctest``, ``py.test`` oder zumindest ``nose`` verwendet.
schlangenbeschwörer hat geschrieben:Und wie trennt man dann Daten und Darstellung, wenn man nicht nur auf die Klasse zugreift, sondern diese auch selbstständig bei bestimmten Gegebenheiten etwas darstellen will?
Die Klasse will aber nie bei bestimmten Gegebenheiten etwas darstellen. Daten sind passiv, auf sie wird zugegriffen. Wenn etwas dargestellt werden soll, muss man das auf höherer Ebene, in einer UI machen, die die Klasse anspricht. Nicht andersrum, sonst wird die Datenlogik mit der Darstellungslogik vermischt.
schlangenbeschwörer hat geschrieben:Der __init__ entsprechende Methoden übergeben, die bestimmte Vorraussetzungen erfüllen? Also so, wie man stdout eine Instanz einer Klasse mit einer write-Methode übergibt?
Würde zwar gehen, stellt dann aber unfassbar komplizierte Anforderungen an die GUI (zumindest wenn sie *etwas* größer sein soll), so dass du jedes Toolkit erstmal dazu bringen müsstest, die von deiner Klasse benötigte API zu haben.
schlangenbeschwörer hat geschrieben:Oder alles mit return regeln, sodass man überprüfen muss, was zurückgegeben wird? Das denke ich, ist wohl besser, aber oft schwer zu machen...
Warum sollte sowas schwer zu machen sein? Und Rückgabewerte überprüfen muss man nicht, wir sind nicht bei C - dafür gibt es Exceptions. Mit einer geeigneten Strukturierung von Exceptions lassen sich Fehler sehr gut behandeln.

Verfasst: Sonntag 27. Mai 2007, 18:48
von schlangenbeschwörer
So, hier:
http://paste.pocoo.org/show/1528/
Hab mal so das geändert, was ich noch komisch fand. Ist jetzt leider ungetestet da untestbar, aber morgen liefer ich dazu ne GUI.
An einigen Stellen hab ich meine Änderungen kommentiert, aber halt nicht an allen...musste dir mal ansehen.

Ach, wozu sollte eigentlich

Code: Alles auswählen

def eingabe_eintragsnummer(nummer):
    try:
        return int(nummer)
    except ValueError:
        return None
gut sein? Das geht doch auch einfacher, oder? Und dann global über der klasse...naja.

edit @ Leonidas: Ich seh grad deinen Beitrag...hab grad nicht mehr so viel Zeit, kannst dir ja mal meine Version ansehen und es "testen".

Mit "selbstständig bei bestimmten Gegebenheiten etwas darstellen" meinte ich auch nicht direkt dieses Programm. ZB bei Spielen, für die man ein GUI schreibt, da kommt sowas häufiger vor. Klingt komisch, GUI für Spiele...

Gruß, jj

Verfasst: Sonntag 27. Mai 2007, 19:11
von rolgal_reloaded
schlangenbeschwörer hat geschrieben:So, hier:
http://paste.pocoo.org/show/1528/
Hab mal so das geändert, was ich noch komisch fand. Ist jetzt leider ungetestet da untestbar, aber morgen liefer ich dazu ne GUI.
An einigen Stellen hab ich meine Änderungen kommentiert, aber halt nicht an allen...musste dir mal ansehen.

Ach, wozu sollte eigentlich

Code: Alles auswählen

def eingabe_eintragsnummer(nummer):
    try:
        return int(nummer)
    except ValueError:
        return None
gut sein? Das geht doch auch einfacher, oder? Und dann global über der klasse...naja.

edit @ Leonidas: Ich seh grad deinen Beitrag...hab grad nicht mehr so viel Zeit, kannst dir ja mal meine Version ansehen und es "testen".

Mit "selbstständig bei bestimmten Gegebenheiten etwas darstellen" meinte ich auch nicht direkt dieses Programm. ZB bei Spielen, für die man ein GUI schreibt, da kommt sowas häufiger vor. Klingt komisch, GUI für Spiele...

Gruß, jj
Kann man eigentlich seinen Code editieren, seh ich es wieder mal nicht oder gehts nicht???

Zur Funktion: die überprüft, ob eine Zahl eingegeben wurde - Auswahl löschen, bearbeiten - diese Funktion ist doch keine sinnvolle Methode der Klasse, denke ich, deshalb steht sie ausserhalb.
Ist doch nichts besonderes, oder?

Die Keys könnte man natürlich schon holen, das probiere ich mal...
aber jetzt weiss ich wieder warum ich es nicht getan habe:

Wenn du die keys mit irgendwas.keys() ausliest bekommst du sie ja nicht in der Ordnung zurück wie du sie in der Anwendung brauchst.

Deine anderen Änderungen muss ich mir erst näher ansehen.

LG

r_r

Verfasst: Sonntag 27. Mai 2007, 22:51
von rolgal_reloaded
So hier mal eine allgemeinere Fassung. Kurz auch drei Beispiele zur Verwendung dieser Klasse. Hauptprogramm fehlt natürlich.

Übrigens gefällt es mir einfach besser, wenn das konkrete Objekt mit dem Konstruktor geladen bzw. gespeichert wird. Diese Klasse ist in ihrer Art sehr nahe an einer fertigen Anwendung und daher empfinde ich es als Vorteil, wenn man sich nach der Instanzierung z. Bsp. nicht mehr um die Abspeicherung kümmern muss.
Laden sollte daher auch keine Methode sein. Geladen wird bei der Instanzierung und solange das Objekt existiert gibts wohl keinen Grund eine Methode laden() darauf anzuwenden.

Gerne diskutier ich über alle meine kühnen Aussagen:-)

Hier der Code:


http://paste.pocoo.org/show/1531/




Zu den vier Fassungen, unflexibel - alles global, alles mit Funktionen, Lösung mit Klasse, Klasse mit abstrahierter Namensgebung werde ich mir jetzt ein ordentliches didaktisches Konzept bauen.
Ich glaube, dass man damit viele Themen rund ums Programmieren effizient besprechen kann.
Bevor ich die ersten beiden Version poste, werde ich nochmal gründlich drüber gehen.

LG

rolgal_reloaded