Gebt mir Tipps

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
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

1. Kontonummer-Attribut

Ich sehe da ja auch einen Zusammenhang, allerdings nur einen mittelbaren (durch die Zuordnung). Zudem möchte ich Redundanzen als Fehlerquellen vermeiden. Wenn die Kontonummer in das Kontoobjekt aufgenommen würde, dürfte sie nicht erneut (redundant) als Schlüssel des dictionaries verwendet werden. Die Frage ist doch, ob das Kontoobjekt die ihm Container übergeordnete Zuordnung (hier dict) kennen muss. Das sehe ich im Moment nicht.

Alternativ böte sich ein set an. Wobei man hier die Kontoklasse (nun mit Kontonummer) und entsprechende Funktionen set-tauglich gestalten müsste.

2. authenticate()-API

Der Gedanke war, dass die API durch ein BankOMat-Objekt, welches die Benutzerschnittstelle definiert, verwendet wird. Dieses Objekt verwendet die Kontonummer als inneren Zustand. Kontonummer vorhanden -> angemeldet, Kontonummer nicht vorhanden (=None) -> nicht angemeldet.

Zugegeben, so sollte man produktiv nicht mit Sicherheit umgehen ;)
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
BlackJack

@bwbg: Ad 1.) Eine Kontonummer gehört zu einem Konto-Objekt, das ist eine Eigenschaft des Kontos, dadurch kann man ein Konto innerhalb einer Bank von anderen Konten unterscheiden. Wenn ich ein Konto-Objekt habe und von dem nicht seine Kontonummer abfragen kann, dann fehlt da etwas. Das hat überhaupt nichts damit zu tun wie ein `Konten`- oder `Bank`-Objekt die `Konto`-Objekte am Ende verwaltet. Wie Du schon sagst, davon sollte ein Konto-Objekt nichts wissen müssen und man sollte nicht wegen Implementierungsdetails wichtige Attribute die zur Problemdomäne gehören einfach weglassen.

Ad 2.) Warum der unnötige Umweg? Warum nicht `Konto`-Objekt vorhanden = angemeldet, `None` = nicht angemeldet? Und selbst Dein Ansatz erklärt immer noch nich die API, denn das liesse sich auch mit einem Wahrheitswert als Rückgabwert der `authenticate()`-Funktion realisieren. Wenn da `True` zurück kommt setzt man die Kontonummer als inneren Zustand, falls `False` zurück kommt eben `None`. Die Kontonummer hat der Aufrufer ja, weshalb ich die API ja schräg finde das die Kontonummer die man sowieso schon hat, als Rückgabwert kommt oder halt `None` was letztlich auf zwei Mögliche Rückgabewert hinaus läuft, also eigentlich ein Wahrheitswert.
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

@BlackJack:
Zu 1) gebe ich Dir recht. Wenn man intensiver darüber nachdenkt, ist es sinnfrei, die Kontonummer getrennt vom Kontoobject zu halten.

Zu 2) bin ich noch nicht ganz überzeugt. None eignet sich doch hervorrangend als (mögliches) Ergebnis für eine Operation, welche fehlschlagen kann. Zumal sich das Ergebnis (durch None) als Wahrheitswert verwenden ließe.

Code sagt mehr als tausend Worte: http://www.python-forum.de/pastebin.php?mode=view&s=429
Anmerkung: Account verfügt (noch) nicht über ein account_id-Attribut.

Hier verwendet die BankOMat.login das von mir vorgeschlagene API-Konstrukt. Die Rückgabe als Wahrheitswert oder gar eine Exception würde das ganze m. E. nach nicht übersichtlicher machen.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

@bwbg: ein

Code: Alles auswählen

if self.bank.authenticate(account_id, password):
    self.account_id = account_id
würde den Code um einiges klarer machen. In Deiner Schreibweise würde sich jeder Leser wundern, wie das Argument account_id mit dem Rückgabewert zusammenhängt. Mit if ist klar, dass es keine zwei verschiedenen account_ids gibt.
BlackJack

@bwbg: Hm, der Entwurf wird IMHO nicht besser. Transaktionen gehören IMHO zum Beispiel zum Konto und nicht zur Bank. Dein Konto-Objekt enthält ja so gut wie gar nichts, dabei wäre das aus Sicht eines Kunden ein zentrales Objekt auf dem so gut wie alles relevante erreichbar ist. Der Titel ist eigentlich eine Verquickung von Kontotyp und Benutzer. Wenn man schon Benutzer und Pins hat, dann würde ich auch eher sagen das Name und Pin in einer `User`-Objekt gehören. Wenn man es einfach halten möchte dann wäre der Kontotyp eine beschreibende Zeichenkette, oder man würde das wenn man die Typen tatsächlich unterscheiden muss über verschiedene Klassen regeln oder das Strategie-Entwurfsmuster anwenden. Der regelmässige Abschluss zum Beispiel sieht ja bei Girokonten anders aus als bei Sparkonten oder internen Konten.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

bwbg hat geschrieben: Zu 2) bin ich noch nicht ganz überzeugt. None eignet sich doch hervorrangend als (mögliches) Ergebnis für eine Operation, welche fehlschlagen kann.
Nicht unbedingt! Im Grunde genommen sind dafür Exceptions oftmals die wesentlich bessere Wahl - denn damit kann ich die Fehlerbehandlung flexibel im Call-Stack behandeln, muss es also nicht unmittelbar an der aufrufenden Stelle tun. Bei einem möglichen ``None`` muss ich eigentlich immer *sofort* prüfen, ob ich etwas bekommen habe, da ich ansonsten *irgend einen* Fehler wie z.B. einen ``AttributeError`` bekomme.

Mal als Beispiel:

Code: Alles auswählen

In [3]: def get_configuration():
   ...:     return None
   ...:

In [4]: config = get_configuration()

In [5]: config.some_property
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-c6a6cf6a3f6f> in <module>()
----> 1 config.some_property

AttributeError: 'NoneType' object has no attribute 'some_property'
[5] ist hier die entscheidene Zeile, in der ich mein Resultat *irgend wie* benutzen will. Ich gehe davon aus, ein bestimmtes Objekt zu bekommen, welches eben ein Attribut ``some_property`` hält. Ich könnte da aber auch eine arithmetische Operation durchführen usw. Dann würde im Call-Stack eine quasi beliebige Exception durchgereicht.

Werfe ich hingegen eine *spezielle* Exception, wenn ich die Konfiguration nicht erstellen kann, so kann ich das zielgerichtet abfangen und zwar dort, wo es sinnvoll erscheint.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Nach einer Nacht drüber schlafen ziehe ich meine Punkte 1 und 2 zurück und behaupte das Gegenteil. Das ganze werde ich nochmal in meine gedankliche Entwurfsabteilung geben.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Mr.White
User
Beiträge: 46
Registriert: Samstag 7. März 2015, 20:03

Sorry, ich komme überhaupt nicht mit. Vielleicht habt ihr ein paar Vorschläge zum lernen für mich. Habe eine Menge
Ideen aber überhaupt keine Ahnung wie ich das mit der Umsetzung mache.. Da währe z.B ein Bot und zum
Code der hier Präsentiert wird - Sowas hab ich noch nie gesehen -
BlackJack

@Mr.White: Es gibt im Netz ein paar Seiten wo man Probleme/Aufgaben findet, die man mit Hilfe von Programmen lösen kann. Mal als Beispiele: Project Euler, Sphere Online Judge (SPOJ), HP CodeWars, und Reddit: Dailyprogrammer.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

@Mr.White, du benutzt Klassen, davon würde ich erstmal abraten.

Lerne erstmal Funktionen sinnvoll einzusetzen.

Dein Code ist momentan ein einziges Spaghetti-Wirrwarr aus If/Else/usw. bis in die zehnte Stufe.

Da kann niemand sinnvoll drüberschauen.

Versuch mal die Sachen in einzelne Funktionen aufzuteilen, die alle nicht tiefer als maximal 2-3 If-Stufen gehen dürfen.

Auch Listen/Dicts würde ich empfehlen zum rumspielen, bevor du wieder Klassen versuchst.

Nicht zu viel gleichzeitig oder zu schnell lernen, das verwirrt eher.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Antworten