Eigenes Objekt?

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.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Hallo,
ich habe mir für mein Kassensystem überlegt dass es recht sinnvoll wäre einen eigenen Objekttyp für Geldmengen zu haben.

Ich möchte das Objekt idealerweise so haben, dass cih damit rechnen kann, es aber mit print z.B. trotzdem als "0,25 €" ausgegeben wird.
Wie kann ich sowas verwirklichen?

Mir fällt da garkein Anfang ein, hoffe ihr wisst da eine Idee.

LG Chris
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ein kleiner Ansatz:

Code: Alles auswählen

>>> class Euro(object):
...     def __init__(self, value):
...         self.value = value
...     def __str__(self):
...         return "%f euro" % self.value
...     def __add__(self, other):
...         return Euro(self.value + other.value)
...
>>> eins = Euro(1)
>>> zwei = Euro(2)
>>> print eins
1.000000 euro
>>> print zwei
2.000000 euro
>>> drei = eins+zwei
>>> print drei
3.000000 euro
>>>
Bei Geld solltest du besser das decimal-Modul benutzen und keine Floats, aber das soll auch nur ein Beispiel sein. Neben "__add__" gibt es noch jede Menge weitere Methoden wie "__sub__", oder "__mul__", die findest du aber alle in der Dokumentation.

Du könntest auch von Decimal erben und die gewünschten Methoden (automatisch) überschreiben. Dazu gab es hier vor kurzem auch einen Thread.
Das Leben ist wie ein Tennisball.
lunar

Eine Währung ist imho kein eigener Datentyp, dieses System wäre auch ziemlich unflexibel.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

lunar hat geschrieben:Eine Währung ist imho kein eigener Datentyp, dieses System wäre auch ziemlich unflexibel.
Nunja, es geht hier ja eher darum dass ich nicht immer mit Floats arbeiten möchte.

Ich möchte einfach eine flexible Möglichkeit in einem Objekt haben.

ich möchte auch ganz einfach folgendes können:

a = Money("0,23€")

print a sollte dann selbiges zurückgeben,
a = a+1
sollte dann allerdings in "1,23€" enden.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Es kommt immer auf den Kontext drauf an, ob Währungen eigenen Datentypen sind oder nicht. Ich möchte nicht einen Euro einfach mit 2 addieren, sondern wieder mit Euro. Wenn man mit vielen verschiedenen Währungen rechnet hat man außerdem den Vorteil, dass man diese über irgend einen Referenzkurs addieren kann.

Es soll da auch eine Raumfahrtbehörde geben, welche, wegen solchen Kleinigkeiten mit Einheiten, Sonden an Planeten vorbei schießt ;-)
Das Leben ist wie ein Tennisball.
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Naja du kannst das €-Zeichen auch später noch dranhängen und einfach float (oder decimal oder sonstwas) benutzen ;)
Oder wenn's dir wirklich so wichtig ist, dass das ganze automatisch abläuft, einfach von float (oder sonstigem) erben und bei __str__ ein € dranhängen.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Nocta, das klingt gut.


das war dann

class Money(float):

oder?

Bevor ihr fragt: Nein, ich brauche das nicht für die Schule, noch ist es privat, meine Ausbildung fängt erst im September an, da lerne ich dann die Grundsätze nochmal neu, noch ist es ein reines Hobby ;-)
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Nein. Warum willst du unbedingt eigene Klassen benutzen? Siehe auch den Post von lunar. Rechne doch einfach mit den Werten, wie du es gewohnt bist und benutze das Decimal-Modul, weil die Genauigkeit bei Währungen eine große Rolle spielt (wurde auch schon erwähnt).
lunar

EyDu hat geschrieben:Es kommt immer auf den Kontext drauf an, ob Währungen eigenen Datentypen sind oder nicht. Ich möchte nicht einen Euro einfach mit 2 addieren, sondern wieder mit Euro.
Die interne Darstellung muss natürlich einheitlich sein. Das aber kann man auch dadurch erreichen, dass Währungen bei der Ein- und Ausgabe entsprechend in bzw. von einer internen Darstellung umgerechnet werden.

Zum einen erleichtert das den Umgang mit verschiedenen Währungen. Ansonsten stellt sich nämlich die Frage, was herauskommen soll, wenn man Euro mit Yen addiert. Zudem vermeidet man so, dass die äußere Darstellung von Werten von deren interner Darstellung abhängt. Werden Beträge in Objekten mit einem Typ entsprechend der Währung gespeichert, sind Typkonvertierungen erforderlich, wenn der Benutzer die verwendete Währung ändert. Andernfalls muss man nur dafür sorgen, dass die Beiträge entsprechend der aktuellen Währung neu angezeigt werden.

Ich persönlich würde zwar einen eigenen Datentyp für einen Geldbetrag verwenden, der bei arithmetischen Operationen mit Ganzzahlen oder Floats warnt, um Umrechnungsfehler zu vermeiden und eine explizite Konvertierung zu erzwingen, keinesfalls aber jede Währung mit einem eigenen Datentyp repräsentieren. Zur internen Darstellung würde ich eine Währung, beispielsweise Euro, verwenden. Alle Ein- und Ausgaben würde ich dann mittels einer weiteren Klasse in Euro bzw. in die bei der Anzeige gewünschte Währung umrechnen. Das hätte auch den Vorteil, dass die Umrechnung zentral implementiert ist, und man so leicht mehrere Datenquellen für Wechselkurse implementieren kann.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Lunar, ich denke du verstehst was ich meine.
Ja, ich möchte es auch z.B. mit Pfund rechnen können.

Als Basis würde ich sehr gerne den Euro nehmen, da meine Software häufig im europäischen Bereich verwendet wird.

Man bräuchte also eine Basisklasse "Euro"

dann bräuchte man Klassen für z.B. Dollar.
Diese bräuchten dann alle eine Methode wie xy.to_euro(), welche ich dann zum Rechnen verwenden könnte.
Das Problem ist nur: Wie mache ich das mit den Objekten? Ich muss sagen, mit Objekten habe ich jetzt eher weniger Erfahrung. Gibt es irgeneine Liste für die ganzen Spezialmethoden wie z.B. __repr__ ?

LG Chris
lunar

Irgendwie habe ich das Gefühl, dass du mein Posting nicht richtig gelesen hast, sonst wüsstest du ja, dass ich eben keine Klassen für jede Währung implementieren würde.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Ein Datentyp ist doch eine Klasse, oder sehe ich das falsch?
lunar

Nein, das ist schon richtig. Ich sagte ja nur, dass ich keinen separaten Datentyp für jede einzelne Währung nutzen würde. Stattdessen würde ich lediglich einen Datentyp für einen Geldbetrag einführen.

Diesen Datentyp könnte man mit zusätzlichen Methoden versehen, die beim Umgang mit Geld hilfreich sind. Außerdem würde ich diesen Datentyp so implementieren, dass man keine "gemischten" arithmetischen Operationen (z.B. "Money(0.25) + 0.25") durchführen könnte. Dadurch erzwingt man eine explizite Konvertierung der Eingabe (die als float vorliegt) über einen Wechselkurs in die intern verwendete Währung. Das verhindert Fehler.

Eine eigene Klasse für jede Währung ist viel zu umständlich und unflexibel.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Hmm, okay, da hast du recht.

Wie fange ich sowas am besten an? Sry, ich kenn mich mit Objekten nicht sonderlich gut aus, das ist für mich Neuland, fasziniert mich aber trotzdem extremst.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Ich würde sowas tendenziell eher wie folgt machen:

Code: Alles auswählen

# coding:utf-8

CURRENCIES = {
        'EUR':1.0,
        "USD":0.765872712
             }

class Money():
    def __init__(self, amount, currency="EUR"):
        self.amount = float(amount)
        self.currency = currency

    def __str__(self):
        return self.amount

    def __add__(self, amount):
        return float(self.amount.get_amount_in_standard_currency() + amount.get_amount_in_standard_currency())

    def __sub__(self, amount):
        return float(self.amount.get_amount_in_standard_currency() - amount.get_amount_in_standard_currency())

    def get_amount_in_standard_currency(self):
        return float(self.amount * CURRENCIES[self.currency])

geld1 = Money(20)
geld2 = Money(15, "USD")


print "Zusammen: %f" % (geld1 + geld2)
print "Abzüglich: %f " %(geld1 - geld2)
Die jeweiligen Währungen werden im dict oben eingetragen. Dabei wird jeweils der gegenwärtige Euro-Kurs der entsprechenden Währung angegeben.

Ganz zufrieden bin ich damit aber auch noch nicht - so wie es jetzt ist, wird man wahrscheinlich ab und an Money()-Objekte und normale ints / floats verwechseln und somit Fehler produzieren (wie lunar schon schrieb). Eigentlich wollte ich dir auch nur kurz zeigen, dass das mit dem Umrechnen eigentlich recht einfach ist und man mit einer Klasse auskommt.

//edit: Also bitte keine Haue, da fehlt sicher noch einiges, um damit arbeiten zu können - ich würde es an deiner Stelle eigentlich wirklich ohne Klassen machen und nur die entsprechenden Umrechnungsfunktionen schreiben.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Hey Barabbas, super, vielen Dank.
Auch wenn ich nicht unbedingt mit etwas fertigem gerechnet hätte (ich bin kein Schüler, ich mache das als Hobby! :-) ) hast du das echt super gelöst.
Vielen Dank, kann ich denke ich fast 1:1 übernehmen und noch erweitern.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Barabbas

Bei mir wirft dein Skript folgende Exception:

Code: Alles auswählen

Traceback (most recent call last):
  File "euro_class_02_01.py", line 29, in <module>
    print "Zusammen: %f" % (geld1 + geld2)
  File "euro_class_02_01.py", line 17, in __add__
    return float(self.amount.get_amount_in_standard_currency() + amount.get_amount_in_standard_currency())
AttributeError: 'float' object has no attribute 'get_amount_in_standard_currency'
Gruss wuf :wink:
Take it easy Mates!
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

achso, es muss nicht "self.amount.get_amount_in_standard_currency()" sondern "self.get_amount_in_standard_currency()" heißen.

Wenn du die beiden betreffenden Zeilen korrigierst, sollte es gehen:

Code: Alles auswählen

# coding:utf-8

CURRENCIES = {
        'EUR':1.0,
        "USD":0.765872712
             }

class Money():
    def __init__(self, amount, currency="EUR"):
        self.amount = float(amount)
        self.currency = currency

    def __str__(self):
        return self.amount

    def __add__(self, amount):
        return float(self.get_amount_in_standard_currency() + amount.get_amount_in_standard_currency())

    def __sub__(self, amount):
        return float(self.get_amount_in_standard_currency() - amount.get_amount_in_standard_currency())

    def get_amount_in_standard_currency(self):
        return float(self.amount * CURRENCIES[self.currency])

geld1 = Money(20)
geld2 = Money(15, "USD")


print "Zusammen: %f" % (geld1 + geld2)
print "Abzüglich: %f " %(geld1 - geld2)
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Bin grade dabei das ganze ein bisschen auszufeilen, jetzt die Frage:
wie heißen die __-Funktionen für die Multiplikation, die Division und das Hochrechnen?

LG Chris
Antworten