Seite 1 von 2

Verfasst: Freitag 17. April 2009, 17:41
von Barabbas
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.

Verfasst: Freitag 17. April 2009, 18:09
von sprudel
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.

Verfasst: Freitag 17. April 2009, 18:13
von wuf
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:

Verfasst: Freitag 17. April 2009, 18:16
von Barabbas
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)

Verfasst: Freitag 17. April 2009, 18:39
von sprudel
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

Verfasst: Freitag 17. April 2009, 18:51
von Barabbas
Hier findest du die entsprechenden Methoden.... http://www.python.org/doc/2.5.2/ref/numeric-types.html

Verfasst: Freitag 17. April 2009, 19:12
von sprudel
Hmm, ich glaube ich stelle mich gerade etwas dumm an:

Code: Alles auswählen

    def __add__(self,amount):
        if type(amount) != "<type 'float'>" and type(amount) != "<type 'int'>": amount = LightMoney(amount)
        return float(self.GetValue()+amount)
    def __sub__(self,amount):
        if type(amount) != "<type 'float'>" and type(amount) != "<type 'int'>": amount = LightMoney(amount)
        return float(self.GetValue()-amount)
    def __mul__(self,amount):
        if type(amount) != "<type 'float'>" and type(amount) != "<type 'int'>": amount = LightMoney(amount)
        return float(self.GetValue()*amount)
    def __div__(self,amount):
        if type(amount) != "<type 'float'>" and type(amount) != "<type 'int'>": amount = LightMoney(amount)
        return float(self.GetValue()/amount)

Das erzielt irgendwie nicht den gewünschen Effekt, was mach ich da falsch?

TypeError: unsupported operand type(s) for /: 'float' and 'instance'

LG Chris

Verfasst: Freitag 17. April 2009, 19:31
von derdon
statt deinen komischen Typüberprüfungen solltest du isinstance nehmen:

Code: Alles auswählen

if isinstance(num, int):
    return 'yes, num is an int!'
Und noch ein Beispiel:

Code: Alles auswählen

if isinstance(num, (int, float)):
    return 'num is either an int or a float'

Verfasst: Freitag 17. April 2009, 21:09
von str1442
type(obj) ist kein String, sondern die Klasse des jeweiligen Objektes (außerdem gibt es auch das .__class__ Attribut bei beliebigen Objekten, aber was man davon nutzt ist sicherlich Stilfrage).

CURRENCIES würd ich definitiv als Klassenvariable benutzen, passt einfach in den Klassenraum rein.

Verfasst: Freitag 17. April 2009, 21:15
von derdon
Getter sind übrigens keine gute Idee (genauso wie Setter).

Code: Alles auswählen

class Money(object):
    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_in_standard_currency + amount.amount_in_standard_currency)

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

    @property
    def amount_in_standard_currency(self):
        return float(self.amount * CURRENCIES[self.currency])

Verfasst: Samstag 18. April 2009, 09:57
von sprudel
was bedeutet das @property ?

Und ich möchte bei isinstance nicht "instance" rauskriegen, sondern was anderes. Wie mache ich das?

LG Chris

Verfasst: Samstag 18. April 2009, 10:25
von Barabbas
Mit Property kannst du eine Klasseneigenschaft (wie amount.amount) an eine Klassenmethode umleiten, so dass du z.B. noch Operationen ausführen kannst, wenn jemand eine Klasseneigenschaft liest / setzt.

Allerdings sehe ich das etwas als derdon: get_amount_in_standard_currency() ist eine normale Klassenmethode - dahinter verbirgt sich ja nicht direkt eine Eigenschaft. Würde ich das ganze umbenennen in "calculate_amount_in_standard_currency()" wäre wahrscheinlich nichtmal moniert worden, dass hier Getter verwendet würden.
Dieses ganze Getter/Setter-Ding bezieht sich m.E. eher darauf, dass man seine Programmierung nicht mehr von vornherein auf G/S auslegen muss, da man mit properties später immernoch entsprechende Methoden implementieren kann. Das heißt aber nicht, dass man alle Methoden, die etwas zurück geben, in Eigenschaften verwandeln muss :wink:

lG

Daniel

Verfasst: Samstag 18. April 2009, 11:34
von HWK
Die __str__-Methode muss auch einen String zurückliefern, z.B.:

Code: Alles auswählen

return str(self.amount)
MfG
HWK

Verfasst: Samstag 18. April 2009, 12:29
von BlackJack
@Barabbas: Man kann aber auch durchaus den Betrag in der Referenzwährung als Eigenschaft von einem "Geldbetrag"-Objekt sehen. Der Name ist natürlich schlecht gewählt, weil `get_*()` eine Tätigkeit beschreibt und deshalb eher zu einer Methode gehört.

Verfasst: Samstag 18. April 2009, 14:51
von Barabbas
ja, habe ich auch erst überlegt - aber prinzipiell hat man ja eine Währung und kann diese durch Umrechnung in eine andere Währung übertragen. Der Betrag einer bestimmten Summe in einer anderen beliebigen Währung ist dann natürlich keine Eigenschaft der ursprünglichen Summe. Daher meine Überlegung. Im Falle der (vorher festgelegten) Referenzwährung könnte man wahrscheinlich aber wirklich darüber streiten.

Aber es ist doch schön, dass man sich beim Entwurf seiner Klassen über solche Dinge Gedanken macht *schwärm*.

Verfasst: Samstag 18. April 2009, 16:13
von str1442
Barrabas: Nenn es lieber Instanzmethode, eine Klassenmethode ist was anderes (help(classmethod)). Und amount ist ein Attribut des Objektes, nicht der Klasse.

Verfasst: Samstag 18. April 2009, 16:41
von Barabbas
*lol* danke für den Hinweis - ich stolpere gerne noch über bestimmte Begrifflichkeiten und bitte um Nachsicht.

Verfasst: Samstag 18. April 2009, 20:34
von Darii
Ich würde es wohl so implementieren(grob orientiert an jscience)
money.py

Code: Alles auswählen

from money import Money, Currency    

EUR = Currency("EUR")
USD = Currency("USD")

# Hier leider Setter notwendig, da properties auf Klassen in python nicht-trivial sind
Currency.set_reference_currency(EUR)
USD.exchange_rate = 0.765872712

print Money(5, USD).convert_to(EUR)
print Money(10, EUR) + Money(5, USD)

Verfasst: Samstag 18. April 2009, 21:00
von Trundle
@Darii: Was meinst du genau mit "nicht-trivial"?

Verfasst: Samstag 18. April 2009, 21:17
von Darii
Siehe Antwort 1: http://stackoverflow.com/questions/1285 ... assmethods , das war mir jedenfalls zuviel Stress für zwei Funktionen. Ich habs auch nur geschrieben, damit nicht irgendwer wegen dem Setter rummeckert...;)