Schlechter Programmierstil?!

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.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

problembär hat geschrieben:Hallo,

grau ist alle Theorie. Deshalb hab' ich's jetzt nochmal so geschrieben, wie ich es machen würde:

http://paste.pocoo.org/show/408421/
Hui... da könnte man jetzt einiges zu sagen...

Mal in Kürze:

- Ein Kunde hat einen Kontostand?

- Du missbrauchst eine Klasse als Modul (`__init__` sieht verdammt grausig aus!)

- kein PEP8 (speziell Methodennamen)

- zu viel Mischung von Benutzerinteraktion und Logik. Eingaben sollte man davon trennen; ggf sogar außerhalb der Klasse erledigen

- über `eur` (Name? Klingt nach Mnemonic :-D ) müsste man nen eigenen Thread aufmachen ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
problembär

Die Fraggles hat geschrieben:Sing und schwing das Bein,
Laß die Sorgen Sorgen sein,
Hat's dir nicht gefall'n,
dann bohr' dir doch ein Loch ins Knie.
Denn manchen kann man's recht oft tun,
doch allen eben nie.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

problembär hat geschrieben:
Die Fraggles hat geschrieben:Sing und schwing das Bein,
Laß die Sorgen Sorgen sein,
Hat's dir nicht gefall'n,
dann bohr' dir doch ein Loch ins Knie.
Denn manchen kann man's recht oft tun,
doch allen eben nie.
Du vermischst hier Intro und Outro :P

Fraggles waren schon cool :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
problembär

Hallo,

na gut, Deine Anmerkungen zu meinem Code sind ja eigentlich auch nicht schlecht.
Hyperion hat geschrieben:Ein Kunde hat einen Kontostand?
Stimmt, das ist etwas unglücklich. Das hatte ich noch von derrick übernommen. Die Klasse sollte wohl eher "Konto" heißen, und statt "self.name", dann "self.inhaber" oder so.

Ich hab' Programmieren ja nicht in der Schule oder an der Uni gelernt, sondern mir diese Sachen selbst angelesen. Dabei komme ich von Sprachen ohne OOP: Früher 8-bit BASIC, dann C (das aber für mich zu schmerzhaft war). Jedenfalls hatte ich immer große Mühe, OOP zu verstehen und auch zu wollen. Bei den Grundlagen geht es jetzt einigermaßen, aber die höhere Theorie ist mir immer noch fremd. Ich mag auch Platon nicht, sondern eher Aristoteles, Kant und die Chinesen (Konfuzius usw.).
Bei Klassen hatte ich einmal das Gefühl, das mit der "Abbildung der Wirklichkeit" sei doch alles nur Gerede. In Wirklichkeit ist eine Klasse technisch einfach nur ein Container, der einige Variablen und Funktionen enthält, die man dann über Instanzen der Klasse ansprechen kann. Interessanterweise habe ich bemerkt, daß diese Sichtweise in Perl auch so umgesetzt wurde: Dort ist eine Klasse ein spezielles "package", wobei ein solches package einfach einen Namensraum definiert und eigentlich dazu gedacht ist, Module zu schreiben.
Aus dieser Sichtweise heraus ist der Name des Containers nicht so wichtig, es ist mehr oder weniger egal, ob der nun "Kunde" oder "Konto" heißt.
An dieser Stelle stehe ich gerade. Und komme ganz gut damit aus. Aber ich schreibe keine saubere OOP. Und weiß auch nicht, ob ich das lernen muß und will. Vielleicht könnt ihr mir etwas Literatur empfehlen (denn "Python GE-Packt", das ich sonst (trotz leichter und vereinzelter Ungenauigkeiten) sehr schätze, ist an dieser Stelle leider etwas dünn)?
Hyperion hat geschrieben:Du missbrauchst eine Klasse als Modul (`__init__` sieht verdammt grausig aus!)
Ok, nach dem oben gesagten, verstehst Du das jetzt vielleicht etwas besser. Obwohl Du's wahrscheinlich immer noch kritisieren wirst.
Hyperion hat geschrieben:kein PEP8 (speziell Methodennamen)
Na ja, man kann nicht alles haben.
Hyperion hat geschrieben:zu viel Mischung von Benutzerinteraktion und Logik. Eingaben sollte man davon trennen; gegebenenfalls sogar außerhalb der Klasse erledigen
Immerhin hab' ich das mit ".getChoice()" schon ein bißchen versucht. Würdest Du das wirklich auch für ganz einfache Eingaben strikt umsetzen?
Hyperion hat geschrieben:über `eur` (Name? Klingt nach Mnemonic :-D ) müsste man nen eigenen Thread aufmachen
Ja, mach' ich wohl bald mal. Die Frage kommt sowieso immer wieder mal. Manche empfehlen da wohl das "locale"-Modul, aber warum sollte man nicht eine eigene kleine Funktion schreiben, die man vollständig unter Kontrolle hat, während man bei dem "locale"-Modul erst sicherstellen muß, daß auch wirklich die richtigen locales eingestellt sind? Für Perl gibt es gleich mehrere Module zur Währungsumwandlung. Es scheint nicht so ganz einfach zu sein, daß für viele Fälle richtig hinzubekommen. Bei meiner Funktion dagegen weiß ich, was sie tut und was man als Rückgabewert erwarten kann. Ich finde das praktischer so. Auch wenn man sie vielleicht noch besser schreiben könnte.

Insgesamt würde mich aber schon interessieren, wie Du das denn mit "richtiger OOP", PEP 8, Pi-pa-po, usw. in orthodoxem Python schreiben würdest.
pillmuncher hat ja auch schon einen Vorschlag gemacht, den ich aber schon vom Konzept her leider kaum nachvollziehen kann (obwohl er bestimmt gut ist, das will ich gar nicht bestreiten).

Aber wichtiger als mein Code war mir eigentlich auch das, was die Aufgabe meiner Meinung nach zeigen sollte (was ich in dem anderen Posting weiter oben beschrieben hatte). Es ist doch erstaunlich, daß hier seitenweise diskutiert wurde, aber dazu bisher niemand etwas geschrieben zu haben scheint.

Gruß
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

problembär hat geschrieben: Aus dieser Sichtweise heraus ist der Name des Containers nicht so wichtig, es ist mehr oder weniger egal, ob der nun "Kunde" oder "Konto" heißt.
Dem wage ich zu widersprechen: Wäre ein Name nicht wichtig, so könnten wir auch alles nur mit x-en, i-s usw. zupflastern. Ein Name ist für das Verständnis des Codes sehr wichtig. Du benutzt aus der Standard-Lib ja auch sachen wie `list`, `sum`, usw. Stell Dir vor diese Funktionen hießen einfach nur `func_a`, `func_b` oder so. Damit wäre es schwer sich zu merken, was die nun genau machen, oder?
Insgesamt würde mich aber schon interessieren, wie Du das denn mit "richtiger OOP", PEP 8, Pi-pa-po, usw. in orthodoxem Python schreiben würdest.
...
Es ist doch erstaunlich, daß hier seitenweise diskutiert wurde, aber dazu bisher niemand etwas geschrieben zu haben scheint.
Naja, man muss ja nicht immer selber eine komplette Lösung abgeben ;-) Und es gab doch iirc einige Lösungen, die ganz gut aussahen - Pillmuncher hatte doch mehrere Lösungen, oder? Muss ich gleich noch mal nachgucken.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

problembär hat geschrieben: Aus dieser Sichtweise heraus ist der Name des Containers nicht so wichtig, es ist mehr oder weniger egal, ob der nun "Kunde" oder "Konto" heißt.
Dem wage ich zu widersprechen: Wäre ein Name nicht wichtig, so könnten wir auch alles nur mit x-en, i-s usw. zupflastern. Ein Name ist für das Verständnis des Codes sehr wichtig. Du benutzt aus der Standard-Lib ja auch sachen wie `list`, `sum`, usw. Stell Dir vor diese Funktionen hießen einfach nur `func_a`, `func_b` oder so. Damit wäre es schwer sich zu merken, was die nun genau machen, oder?

Noch schlimmer: Du hast eine Funktion `list`, die in Wirklichkeit ein DIctionary erstellt und Dich somit auf die falsche Fährte lenkt? Natürlich mag man sich über Kunde vs. Konto streiten können, aber letztlich hilft es imho dabei, sich sinnvolle Namen für Klassen auszudenken, die beim Leser genau die Idee hinter der Klasse und ihrer Funktionlität induziert.
Insgesamt würde mich aber schon interessieren, wie Du das denn mit "richtiger OOP", PEP 8, Pi-pa-po, usw. in orthodoxem Python schreiben würdest.
...
Es ist doch erstaunlich, daß hier seitenweise diskutiert wurde, aber dazu bisher niemand etwas geschrieben zu haben scheint.
Naja, man muss ja nicht immer selber eine komplette Lösung abgeben ;-) Und es gab doch iirc einige Lösungen, die ganz gut aussahen - Pillmuncher hatte doch mehrere Lösungen, oder? Muss ich gleich noch mal nachgucken.[/quote]
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
daemonTutorials
User
Beiträge: 171
Registriert: Sonntag 6. Februar 2011, 12:06
Kontaktdaten:

Hey derrick,
ich muss dich beruhigen, ich habe als erstes auch prozedural und schrecklich geschrieben, eben so wie es funktioniert. Jetzt weiß ich, dass die OOP sehr nützlich sein kann, nicht immer aber oft!

Anmerkung zu diese __init__-Funktion die irgendwo angesprochen wurde: Ein Konstruktor ist nur dafür da, um eventuelle Variablen zu instanzieren, also globale Variablen schon am Anfang aus einer Config-Datei abrufen( dieses Vorgehen in eine Funktion außerhalb der Klasse kapseln) oder um auch Variablen zu speichern, die der Klasse übergeben wurden.

Beispiel:

Code: Alles auswählen

#!/usr/bin/python3

def readconf():
    f = open("conf.txt", "r")
    return f.read()

class MyProgram():
    def __init__(var1, var2):
        self.glob_var1 = var1
        self.glob_var2 = var2
   
        self.config = readconf()
        self.parseConfig()

    def parseConfig():
        # Hier wird z.B. die Configfile geparst, oder ähnliches
        pass

    def run():
        self.start_app()

  ###################
 # Test function          #
###################

if __name__ == "__main__":
    myapp = MyProgram(250, "hours later")
    myapp.run()
Das sollte veranschaulichen wie man denn einen Konstruktor richtig verwendet.
Hier ein Merksatz:
Klassen sind Klassen, die Klasse macht nix, solange der Benutzer der Klasse diese Events nicht anstößt.
Dinge, die etwas am Programm selber verändern, muss der Benutzer der Klasse auslösen, nicht die Klasse selber.
Die Klasse selber darf z.B. kein neues Fenster öffnen, das muss der Benutzer der Klasse initalisieren.
Klassen sind Sammlungen von Funktionen die aufeinander aufbauen, eine Klasse fasst einfach und strukturiert eine Sammlung an Funktionen zusammen.
Durch Klassen und OOP kann man die gezwungene Verwendung von 'global' meistens abwenden.
Ich hoffe dir ist klar geworden, was eine Klasse darstellt, und was deren Recht ist!
LG Maik
Antworten