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.
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
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Hier findest du die entsprechenden Methoden.... http://www.python.org/doc/2.5.2/ref/numeric-types.html
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

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
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

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'
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

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.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

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

was bedeutet das @property ?

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

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

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
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Die __str__-Methode muss auch einen String zurückliefern, z.B.:

Code: Alles auswählen

return str(self.amount)
MfG
HWK
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.
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

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*.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Barrabas: Nenn es lieber Instanzmethode, eine Klassenmethode ist was anderes (help(classmethod)). Und amount ist ein Attribut des Objektes, nicht der Klasse.
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

*lol* danke für den Hinweis - ich stolpere gerne noch über bestimmte Begrifflichkeiten und bitte um Nachsicht.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

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)
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

@Darii: Was meinst du genau mit "nicht-trivial"?
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

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...;)
Antworten