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

@rolgal_reloaded: Diese Schrittweise Umwandlung mit einem "beweglichen Ziel" ist wahrscheinlich keine gute Idee gewesen.

Ein Entwurf der funktioniert ist dadurch nicht automatisch gut. paste.pocoo.org hat gerade mal wieder einen "Internal Server Error"[*], darum habe ich jetzt keinen Zugriff auf die letzte Version. Entwurf ist ein Prozess und das Endergebnis sieht für mich nicht so aus, als wenn der nicht besonders geradlinig verlaufen ist. Was wie gesagt, höchstwahrscheinlich damit zu tun hat, dass es mehr gewachsen als geplant ist. Die Methoden beschränken sich nicht nur auf eine Aufgabe, wie `__init__()`, das auch das Laden übernimmt, oder `__str__()`, das ein in der Dokumentation nicht vorgesehenes Argument bekommt und dafür explizit aufgerufen werden muss. Dann ist in der Klasse "GUI" und Datenhaltung vermischt. Es ist aber auch nicht die ganze "GUI" in der Klasse enthalten, also kann man es auch nicht als Anwendungsobjekt sehen. Das sind alles schlechte Beispiele und die sollte man als Lehrer möglichst nicht bringen. Schüler werden das als Muster für künftige Programme benutzen. So etwas wie Sternchen-Import, ``global``, ``input`` und ``eval`` sollte man gar nicht erst einführen und Punktabzug geben, wenn es jemand benutzt, ohne genau erklären zu können warum das im Allgemeinen schlecht ist und genau bei *dem* Einsatz eine Ausnahme von der Regel gerechtfertigt ist. IMHO.

Das es nicht nur etwas mit OOP zu tun hat, vermute ich, da ich nicht sehe das hier eine klare Anforderung in eine Datenstruktur umgesetzt wurde, sondern es mit der Zeit gewachsen ist. Ich denke das wird in der imperativen Variante ähnlich aussehen.

Ich habe ja offensichtlich keine grosse Erfahrung mit Lehre, aber ich würde folgenden Ablauf für ganz gut halten: Klare Anforderung worauf man hinauswill, Datenstrukuren auswählen und begründen, die benötigten Operationen herausarbeiten, und diese dann als einzelne Funktionen implementieren. Dabei immer darauf achten, das sie von den Schülern einzeln ausprobiert und "erfahren" werden können. Dabei sollte dann ein Ansatz herauskommen, der sich sehr einfach in OOP umsetzen lässt, weil ein guter imperativer Entwurf gar nicht soweit von OOP entfernt sein muss. Im Grunde müssen dabei nur zusammengehörige Datenstrukturen und Funktionen zu Attributen und Methoden zusammengefasst werden.

[*] @pocoo-Menschen: Ich weiss, es ist ein kostenloser Service und man kann leicht meckern bei Sachen, für die man nicht verantwortlich ist, aber der Service ist in letzter Zeit verdammt unzuverlässig. Woran liegt das? Ist der paste-Service selber nicht stabil oder liegt's daran, dass der auf einem Server läuft, auf dem auch andere Komponenten aktiv in der Entwicklung und damit nicht immer so ganz stabil sind?
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben: Die Methoden beschränken sich nicht nur auf eine Aufgabe, wie `__init__()`, das auch das Laden übernimmt,
Es gehört eben wie schon begründet bei der Instanzierung dieser Objekte dazu
....oder `__str__()`, das ein in der Dokumentation nicht vorgesehenes Argument bekommt und dafür explizit aufgerufen werden muss.

Das sehe ich jetzt mal etwas locker, wenn es eine ganz einfache andere Lösung - integrierbar in meinen Code, gibt, dann gern
Dann ist in der Klasse "GUI" und Datenhaltung vermischt. Es ist aber auch nicht die ganze "GUI" in der Klasse enthalten, also kann man es auch nicht als Anwendungsobjekt sehen.
Du hast auch ein raw_input in deinem Beispiel, erwischt, ggg.
Aber darüber habe ich natürlich auch schon nachgedacht, aber halt noch keine Lösung dafür.
Das sind alles schlechte Beispiele und die sollte man als Lehrer möglichst nicht bringen........
Wenn das immer möglich wäre ohne schlechte Beispiele auszukommen, ich meine auch mein Hauptfach, dann würde ich doppelt so gern unterrichten.
Das es nicht nur etwas mit OOP zu tun hat, vermute ich, da ich nicht sehe das hier eine klare Anforderung in eine Datenstruktur umgesetzt wurde, sondern es mit der Zeit gewachsen ist. Ich denke das wird in der imperativen Variante ähnlich aussehen.
Das stimmt. Allerdings habe ich auf diesem Weg erkannt was eine wesentlich bessere Datenstruktur ist. Erinnerst dich vielleicht noch an die alte?
Ich habe ja offensichtlich keine grosse Erfahrung mit Lehre, aber ich würde folgenden Ablauf für ganz gut halten: Klare Anforderung worauf man hinauswill, Datenstrukuren auswählen und begründen, die benötigten Operationen herausarbeiten, und diese dann als einzelne Funktionen implementieren. Dabei immer darauf achten, das sie von den Schülern einzeln ausprobiert und "erfahren" werden können. Dabei sollte dann ein Ansatz herauskommen, der sich sehr einfach in OOP umsetzen lässt, weil ein guter imperativer Entwurf gar nicht soweit von OOP entfernt sein muss. Im Grunde müssen dabei nur zusammengehörige Datenstrukturen und Funktionen zu Attributen und Methoden zusammengefasst werden.
Auf die Gefahr hin, dass ich gleich wieder durch den Fleichwolf gedreht werde, poste ich mal die Variante mit Funktionen. Ich finde, dass der letzte Satz deines Absatzes ziemlich genau zutrifft.
Aber gucken wir mal....

http://www.ubuntuusers.de/paste/11148/
BlackJack

Man könnte zum Beispiel eine Methode `_entries2str()` einführen und die von `__str__()` und der Suche aus benutzen. Ansonsten verhindert das Laden in der `__init__()` eine mögliche Lösung, nämlich dass die Suche ein `DataBook`-Objekt liefert, dass man einfach ausgeben kann.

Du hast zwar Deine imperative Lösung relativ direkt in Klassen und Methoden umgesetzt, aber ich finde die imperative Lösung auch nicht gut. Kein Wunder dass die OOP-Lösung nicht besser wird. ;-)

Dein einer Datentyp vermischt Datensätze, die Datenbank und die Anwendung. Ein sauberer Entwurf hätte ein Datenbank-Objekt, das Datensatz-Objekte enthält und die Anwendung wäre entweder auch ein Objekt oder als Funktionen auf Modulebene implementiert.

Zur Modellierung: Ein Datensatz braucht Schlüssel und Werte, in der Datenbank selbst allerdings reicht es die Schlüssel nur einmal zu speichern und von den Objekten nur die Werte. Und was Datensätze im Grunde auch brauchen ist eine eindeutige ID. Solange man mit dem Programm nicht folgenden Arbeitsablauf bewerkstelligen kann: Eine Suche starten und einfach einen Datensatz im Suchergebnis bearbeiten, ist das genauso sinnlos wie Fahrzeuge als Klassen. Und das wolltest Du ja nicht. :-)
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

@BlackJack

Du müsstest wissen, dass wenn es mir um eine prof., soll heissen richtige Anwendung ginge, ich es sowieso anders gelöst hätte.

Inzwischen denke ich ist es sinnlos zu versuchen zu erklären, was der Unterschied ist zwischen Programmen, die ansehnlich, funktional, lehrreich sind - weil vieles rund ums Programmieren demonstriert werden kann, und solchen die echte Programme sind.

Es ist jetzt auch der Punkt erreicht wo ich darüber nicht mehr diskutieren mag.
Irgendwas wird nicht gelesen, verstanden oder gehört, sonst würdest du mir gar nicht erklären, dass der imperative Ansatz auch nicht gut ist.

Ich werde weiterhin als schlechter Programmierer schlechte Programme schreiben, hoffe bei Problemen weiterhin sinnvolle Hilfe zu bekommen und bin froh, dass die Bestätigung für meine trotzdem produktive Arbeit nicht allein von den Leuten in diesem Forum mit ihren für meinen Anwendungszweck inkompatiblen Kriterien abhängig ist.

LG

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

Du hast zwar Deine imperative Lösung relativ direkt in Klassen und Methoden umgesetzt, aber ich finde die imperative Lösung auch nicht gut. Kein Wunder dass die OOP-Lösung nicht besser wird. ;-)

Dein einer Datentyp vermischt Datensätze, die Datenbank und die Anwendung. Ein sauberer Entwurf hätte ein Datenbank-Objekt, das Datensatz-Objekte enthält und die Anwendung wäre entweder auch ein Objekt oder als Funktionen auf Modulebene implementiert.

usw., usw.
Da muss man sich auch fragen, warum du dann überhaupt auf Seite 1 deine Vorschläge zur Verbesserung gemacht hast, wenn diese den Ausführungen oben entsprechend, ja gar keine sein können.
:?:

Du hattest da sogar noch viel mehr in den Funktionen drin was nicht reingehört, wie du dich vielleicht noch erinnern kannst.

Dennoch war es ein guter Anstoß in die richtige Richtung weiterzudenken.

LG

rolgal_reloaded
BlackJack

Daran kann ich mich nicht erinnern und auch auf Seite 1 nicht nachlesen. Da habe ich ein paar Verbesserungsvorschläge zu den Funktionen gemacht. Und auch zugegeben, dass man die GUI aus den Funktionen noch herausziehen müsste.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:Daran kann ich mich nicht erinnern und auch auf Seite 1 nicht nachlesen. Da habe ich ein paar Verbesserungsvorschläge zu den Funktionen gemacht. Und auch zugegeben, dass man die GUI aus den Funktionen noch herausziehen müsste.
Du hattest z. Bsp. auch den Aufruf der Funktion zur Überprüfung, ob die Eingabe einer Zahl entspricht, in den einzelnen Funktionen drin,......mir gings jetzt aber nicht zu pressen: Hoho, ich hab was gefunden was an deinem Code schlecht ist.

Worum es ging wird hoffentlich so auch klar sein, werden, weil es schon oft genug erklärt wurde von mir.

Wäre doch klasse, wenn wir für die verschiedensten Fragestellungen mit ihren spezifischen Zielsetzungen eine konstruktive Gesprächsbasis hätten.

LG

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

Hallo,

hab mal kleine Sachen geändert, Pfad ist auch wählbar, und min_entries habe ich auf 0 gesetzt.


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


Wenn ich jetzt weiterdenke und mich an Überlegungen auch Methoden wie __len__ u.a. zu implementieren, fragte ich mich, ob man nicht überhaupt von list() ableiten sollte. Schließlich ist es eine Liste.

Grundsätzlich frage ich mich auch, ob es nicht auch möglich sein sollte Werte bei der Instanzierung zu übergeben. Wäre ja wohl nicht so die große Sache.
Ist es wirklich nötig, meistens erzeugt man doch leere Objekte von Klassen wie list() u. ä.

Was meint ihr dazu?

LG

r_r
BlackJack

Ich persönlich würde hier nicht von `list()` ableiten. Man bekommt damit Methoden die keinen Sinn machen, wie zum Beispiel die Multiplikation, oder `pop()`, was man bei einer Datenbanktabelle nicht erwartet. Ausserdem brauchen die Datensätze IMHO auch immer noch eine eindeutige ID und ein Zugriff per Indexoperator über eine ID macht mehr Sinn als über den Index. Und damit dann die ganzen `list()`-Methoden korrekt funktionieren müsste man sie wohl eh alle überschreiben.

Wenn man Werte bei der `__init__()` angeben könnte, dann wäre meine Lösung mit der Ausgabe des Suchergebnisses ja plötzlich möglich. :-)

Ich hole übrigens gerade zu einer längeren Antwort aus, das kann aber noch dauern.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:Ich persönlich würde hier nicht von `list()` ableiten. Man bekommt damit Methoden die keinen Sinn machen, wie zum Beispiel die Multiplikation, oder `pop()`, was man bei einer Datenbanktabelle nicht erwartet. Ausserdem brauchen die Datensätze IMHO auch immer noch eine eindeutige ID und ein Zugriff per Indexoperator über eine ID macht mehr Sinn als über den Index. Und damit dann die ganzen `list()`-Methoden korrekt funktionieren müsste man sie wohl eh alle überschreiben.
Jo, stimmt, das leuchtet alles ein. Irgendwie hätte mir die Idee gefallen, demonstrieren zu können wie praktisch das ist, wenn man erben kann.
Aber das steht eindeutig nicht dafür.
Muss ich wohl bei meiner Klasse sortdict bleiben.

Wenn man Werte bei der `__init__()` angeben könnte, dann wäre meine Lösung mit der Ausgabe des Suchergebnisses ja plötzlich möglich. :-)
Mir dämmert schon wie,....
Allerdings laden, ggg.........außer:
Wenn man eine Option übergeben kann, ob man laden will oder nicht, das wäre doch eine gangbare Lösung? Und suchen müsste diese Option automatisch richtig setzen...
Ich hole übrigens gerade zu einer längeren Antwort aus, das kann aber noch dauern.
Lass dir ruhig Zeit, ich habs nicht eilig, besonders nicht beim Programmieren.

LG

rolgal_reloaded
Zuletzt geändert von rolgal_reloaded am Dienstag 29. Mai 2007, 21:25, insgesamt 1-mal geändert.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Mir dämmert schon wie,....
Allerdings laden, ggg.........außer:
Wenn man eine Option übergeben kann, ob man laden will oder nicht, das wäre doch eine gangbare Lösung? Und suchen müsste diese Option automatisch richtig setzen...
So könnte das z. Bsp. aussehen:
http://paste.pocoo.org/show/1538/

__str__ entspricht wieder der Doku, also was die Sache mit dem Argument betrifft und search() erzeugt einfach ein neues Objekt.
Was mich selbst jetzt ad hoc stört ist, dass die Rumreicherei von filename.
Das muss doch eleganter gehen?
Testen auf True und ggf. eine Standarddateinamen zuweisen, abgeleitet vom Instanznamen, sowas vielleicht?

@edit:

Oder einfach: Der Pfad muss den Dateinamen schon beinhalten, dann muss filename nicht separat angegeben werden...habe ich aber auch Zweifel....

Ob jetzt durch die Änderungen irgendwelche neue Fehler auftreten können, habe ich noch nicht getestet - bitte melden:-) Danke:-)


LG

rolgal_reloaded
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Also das funktioniert so nicht: Wenn kein path angegeben wird ist path default mäßig None und es knallt in der else Bedingung )

Code: Alles auswählen

    def __init__(self, filename,
                 keys, entries = [],
                 temp = False, path = None,
                 min_entries = 0):

        self.filename = filename
        self.keys = keys
        self.entries = list()
        self.min_entries = min_entries        
        
        if path is not None:
            self.path = path + "/" + filename
        else:
            self.path = self.path + "/" + filename # PENG! ;)
Hab die sonstige Diskusion nicht mitverfolgt, aber das ist mir gerade so aufgefallen. Ich würde Pfade immer mit os.path.join() erstellen als mit + Operatoren zusammenzuschustern.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Hier stellen sich bei mir so ein paar Fragen: (sorry wenn ich vielleicht angesprochenes wiederhole)

Edit: Hat sich erledigt, falsch gelesen.....
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Zap hat geschrieben:Also das funktioniert so nicht: Wenn kein path angegeben wird ist path default mäßig None und es knallt in der else Bedingung )
Nein, da knallt es nicht. Denn wenn der Pfad nicht angegeben wird, dann wird der Standardpfad, der sich aus der Klassenvariable ergibt verwendet.
So war es gedacht und so hat es bei mir auch funktioniert.

LG

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

@alle

Jetzt habe ich es doch eingesehen und das Laden rausgenommen.
Der Konstruktor wurde jmit der letzten Fassung schon etwas unhandlich und diesen didaktisch aufbereiten wird wohl eher ungemütlich.

Ich muss es noch ein bisschen testen, dann poste ich den Code.

LG

rolgal_reloaded
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

rolgal_reloaded hat geschrieben:
Zap hat geschrieben:Also das funktioniert so nicht: Wenn kein path angegeben wird ist path default mäßig None und es knallt in der else Bedingung )
Nein, da knallt es nicht. Denn wenn der Pfad nicht angegeben wird, dann wird der Standardpfad, der sich aus der Klassenvariable ergibt verwendet.
So war es gedacht und so hat es bei mir auch funktioniert.
Edit: ups, ok sorry :oops:. Ist wohl nicht mein Tag ;)
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

So hier ist sie, müsste alles klappen!


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


LG

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

Hallo,

oben gezeigtes Beispiel hat immer noch das Problem, dass es in den Funktionen Aufrufe von raw_input() gibt. Dadurch müsste man die Funktion für eine GUI erst wieder anpassen. Ich habe mal gedacht, ob folgender Weg ein Lösungsansatz sein könnte. Die Übergabe einer Funktion wie entry.get() einer Mega MiniGUI hat leider nicht funktioniert.
Mit raw_input() schon....

Code: Alles auswählen

>>> def test(funktion):
	    eingabe = funktion
	    return eingabe

>>> test(raw_input())
50
'50'
@edit:

Geht doch auch mit einer GUI, es bleibt allerdings zu fragen, ob das dann eine saubere Lösung ist.
Das müssten jetzt mal die GUI Experten hier sagen.

LG

r_r
BlackJack

Die `test()`-Funktion verstehe ich nicht so ganz. Die macht ja rein gar nichts. Die gibt einfach nur dass zurück was man ihr übergeben hat. Das lässt sich auch so schreiben:

Code: Alles auswählen

def identity(obj):
    return obj
So eine Identitätsfunktion ist bei funktionaler Programmierung manchmal ganz praktisch, aber hier!?
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

@BlackJack

Na ich dachte: anstatt raw_input() z. Bsp. in die Funktion edit() bzw. bearbeiten() zu schreiben, muss ihr die Funktion mit der die Datein eingegeben werden oder bei einer GUI ausgelesen werden übergeben werden. Bei test() fehlt natürlich alles was dann mit den eingegebenen Daten weiter passiert.

Klar was ich meine?

LG

r_r
Antworten