kleine Mathe-Spielereien

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

23.6.2025
von 'class angebot'
habe ich mir eine weitere Version gebastelt.
'Übung macht den Meister' und ist besser lesbar.
OSWALD

Code: Alles auswählen


              KIOSK VERKSUFSANGEBOT
class Angebot:
    def __init__(self, product_id, name, price, quantity, **kwargs):
        self.product_id = product_id
        self.name = name
        self.price = price
        self.quantity = quantity

        ## Add any additional attributes provided
        for key, value in kwargs.items():
            setattr(self, key, value)

    def total_value(self):
        return self.price * self.quantity

    def display_info(self):
        result = [f"Angebot: {self.name} (ID: {self.product_id})",
                  f"Price: €{self.price:.2f}",
                  f"Quantity: {self.quantity}",
                  f"Total Value: €{self.total_value():.2f}"]

        ## Display additional attributes
        standard_attrs = {'product_id', 'name', 'price', 'quantity'}
        for attr in dir(self):
            if not attr.startswith('__') and not callable(getattr(self, attr)) and attr not in standard_attrs:
                value = getattr(self, attr)
                result.append(f"{attr.replace('_', ' ').title()}: {value}")

        return '\n'.join(result)


class Verkauf:
    def __init__(self):
        self.products = {}

    def add_product(self, product):
        self.products[product.product_id] = product
        print(f"Added: {product.name}")

    def update_attribute(self, product_id, attribute, value):
        if product_id in self.products:
            product = self.products[product_id]
            old_value = getattr(product, attribute, None)
            setattr(product, attribute, value)
            print(f"Updated {attribute} of {product.name} from {old_value} to {value}")
            return True
        print(f"Product with ID {product_id} not found.")
        return False

    def display_verkauf(self):
        if not self.products:
            print("Verkauf")
            return

        print("\n===== Current Inventory =====")
        total_value = 0
        for product in self.products.values():
            print(f"\n{product.display_info()}")
            total_value += product.total_value()

        print(f"\nTotal Verkauf Value: €{total_value:.2f}")
        print("============================")

print("#IMPLENTIEREN #################################")

verkauf = Verkauf()

## Create products with additional attributes
kaffee = Angebot(1, "Kaffee", 3.50, 5)
wiener = Angebot(2, "Wiener", 4, 10)
eiskaffee =Angebot(3, "Eiskaffee ",6 ,25)
bratwurst = Angebot(4, "Bratwurst", 9, 5)
kuchen    = Angebot(5,"Kuchen",3.50,7)
## Verkaufte Produkte 
verkauf.add_product(kaffee)
verkauf.add_product(wiener)
verkauf.add_product(eiskaffee)
verkauf.add_product(bratwurst)
verkauf.add_product(kuchen)
## Display the inventory
verkauf.display_verkauf()

## Update a standard attribute
verkauf.update_attribute(5, "price", 5)
verkauf.update_attribute(4, "price" ,3)
## Update a custom attribute
 
## Add a new attribute to an existing product
verkauf.update_attribute(2, "price", 13)

## Display the updated inventory
verkauf.display_verkauf()




Benutzeravatar
snafu
User
Beiträge: 6854
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

OSWALD hat geschrieben: Montag 23. Juni 2025, 15:32 3.' OOP- Class ' scheint mir für 'Zahlenthemen' besser geeignet als für Strings
OOP ist einfach die Kapselung von Zustand, Verhalten und Logik. Vor allem kann man sich den Zustand damit relativ einfach über mehrere Aufrufe merken bzw. verwenden. Außerdem erscheint OOP - wenn richtig angewendet - oft "greifbarer", weil man sich reale Objekte dahinter vorstellen kann.

Ein gutes OOP-Design ist allerdings sehr herausfordernd. Du bist quasi der Architekt deiner "Objekt-Welt". Man erwischt sich schnell dabei, dass man stellenweise eigentlich nur eine Ansammlung von Funktionen gebastelt hat, die sich via "self" aufrufen und trotzdem das gleiche Argument herumreichen. Wenn man so etwas hat, sollte man den Ansatz infrage stellen und überlegen, wie man mehr Objektorientierung hinein bekommt.

Jedenfalls lässt sich das nicht an der Frage festmachen, ob man Zahlen oder Strings vorliegen hat. Python selbst hat - wie viele andere Sprachen auch - den Datentyp "str" als Objekt mit Methoden implementiert. Warum sollte das weniger gut für OOP geeignet sein als eine zahlenlastige Klasse?

Im Übrigen sind simple String-Kodierungen wie ASCII nichts anderes als eine Zahlenfolge, welche die Positionen der einzelnen Zeichen im vorliegenden Zeichensatz angeben. Und in komplexeren Formaten wie Unicode stecken mehr logische Operationen mit Zahlen als du vielleicht denkst.
OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

24.6.2025
An snafu
Als Lehrling hier im Forum würde ich mir nie erlauben
auch nur die geringste Kritik an Python bzw. OOP zu üben.
Ich hätte vielleicht sagen sollen, dass mir generell als
Zahlenmensch der Umgang mit 'strings' viel schwerer
erscheint als der mit Zahlen. Das ist mir bei der Beschäftigung
mit Matrizen besonders aufgefallen.
Das Prinzip *Form und Inhalt* ist halt immer sehr schwer zu realisieren.
Die Voraussetzungen für das Erlernen und Verstehen von Python etwa
sind schon sehr hoch, weil Python selbst genial und sehr komplex ist.
Python ist mein Hobby
OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

24.6.25
OOP
Hier zunächst das Prinzip der Vererbung.
Ausführliches Beispiel folgt.
OSWALD

Code: Alles auswählen


#VERERBUNG  TIER    >>>>>> BauplanHundeKlasse(Tier)
#YERERBUNG  TIER   >>>>>>>BauplanVÖGELKlasse(Tier)
 
class Tier():
    def __init__(self, rufname, farbe, alter):
        self.rufname = rufname
        self.farbe   = farbe
        self.alter   = alter
         
##################################
class BauplanHundeKlasse(Tier):       
    ""
    def __init__(self, rufname, farbe, alter):
        """ Initalisieren über Eltern-Klasse """
        super().__init__(rufname, farbe, alter)
hund_wauwau = BauplanHundeKlasse("Wauwau", "braun", 6)
print(hund_wauwau.farbe)
     
 
##############################
 
class BauplanVogelKlasse(Tier):
    

    def __init__(self, rufname, farbe, alter):         ### hier  Initialisierung
        """ Initalisieren über Eltern-Klasse """
        super().__init__(rufname, farbe, alter)        

papagei_lora = BauplanVogelKlasse("Lora", "bunt", 5)
print(papagei_lora.rufname)


Benutzeravatar
__blackjack__
User
Beiträge: 14019
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das ist vielleicht syntaktisch ein Beispiel für Vererbung aber inhaltlich nicht. Und die `__init__()`-Methoden bei den abgeleiteten Klassen machen nichts sinnvolles, die kann man einfach weglassen, ohne das sich etwas am Programmablauf verändert.

Die Namensgebung macht auch keinen Sinn. Ja Klassen sind Klassen. Und Klassen sind Baupläne. Das bringt also nichts das noch mal im Klassennamen zu erwähnen. `Tier` heisst ja auch nicht `BauplanTierKlasse`, obwohl auch das ein Bauplan/eine Klasse ist.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

25.6.25
@blackjack
diese Definition habe ich dem Internet entnommen ,weil
die mir bisher bekannte Syntax des Begriffes Vererbung etwas
anders aussah( 'super' ??? usw).
Nun hoffe ich, dass jetzt alles stimmt.
Hier meine Version für Vererbung.
Gute Zeit OSWALD

Code: Alles auswählen


class Konto(object): 
    """ Basis Konto Klasse """

    def __init__(self, inhaber, kontonummer, kontostand): 
        """ Konstruktor, Aufruf bei Instanzierung """                
        print( ".. Konto anlegen")
        self.Inhaber = inhaber 
        self.Kontonummer = kontonummer 
        self.Kontostand  = kontostand 
        self.zeige_konto()

    def einzahlen(self, betrag): 
        """ Mach eine Einzahlung """
        print (".. Einzahlen   : %i %5.1f" % (self.Kontonummer, betrag))
        self.Kontostand  += betrag 
 
    def auszahlen(self, betrag): 
        """ Mach eine Auszahlung """
        print( ".. Auszahlen   : %i %5.1f" % (self.Kontonummer, betrag))
        self.Kontostand  -= betrag 


##########Achtung die Methode ueberweisung wurde  aus Class Girokonto nach class Konto kopiert
    def ueberweisung(self, ziel, betrag): 
        """ Mach eine Ueberweisung """
        print( ".. Transfer    : %i %s %i %5.1f" % (self.Kontonummer, "->", ziel.Kontonummer, betrag))
        self.Kontostand  -= betrag 
        ziel.Kontostand  += betrag 

    def zeige_konto(self): 
        """ Zeige die Kontodaten am Bildschirm """
        print( ".. Konto       :", self.Inhaber)
        print( "   Kontonummer :", self.Kontonummer)
        print( "   Kontostand  :", self.Kontostand )

#############################
class Girokonto(Konto): 
    """ Giro Konto Klasse """

    def __init__(self, inhaber, kontonummer, kontostand, sollzinsen, habenzinsen): 
        """ Giro Konstruktor, Aufruf bei Instanzierung """                
        self.__Sollzinsen = sollzinsen
        self.__Habenzinsen = habenzinsen
        # initialisiere Konto
        Konto.__init__(self, inhaber, kontonummer, kontostand)
############# Hier liegr der Hund begraben
    def ueberweisung(self, ziel, betrag): 
        """ Mach eine Ueberweisung """
        print( ".. Transfer    : %i %s %i %5.1f" % (self.Kontonummer, "->", ziel.Kontonummer, betrag))
        self.Kontostand  -= betrag 
        ziel.Kontostand  += betrag 

##################################
class Sparkonto(Konto): 
    """ Sparbuch Konto Klasse """
    
    def __init__(self, inhaber, kontonummer, kontostand, zinssatz): 
        """ Spar Konstruktor, Aufruf bei Instanzierung """                
        self.Zinssatz = zinssatz
        # initialisiere des Kontos
        Konto.__init__(self, inhaber, kontonummer, kontostand)

    def zeige_konto(self): 
        """ Zeige die Kontodaten am Bildschirm, ueberschreibt Konto Funktion """
        Konto.zeige_konto(self) 
        print( ("   Zinssatz    :", self.Zinssatz ))
        

if __name__ == '__main__':
    
    print( "\nKontobeispiel mit Vererbung")
    
    # Erzeuge zwei Konto-Objekte
    kg = Girokonto("Oswald Meier", 78340, 120, 0.05, 0.01) 
    ks = Sparkonto("Oswald  Meier", 78341,  40.0, 0.03)  
    km= Konto("Klaus Freund",78200, 50)
    km = Girokonto("Klaus Freund", 78300, 150, 0.05,0.01)
               
    print( "------------------------------")
    
    # Mach was damit ...
    print("=Oswald Meier zahlt ein auf Girokonto:")
    kg.einzahlen(333333)
    print("Oswald  Meier zahlt ein auf Sparkonto")
    ks.einzahlen(5555)    
    print("Oswald Meier zahlt aus von Sparkonto")
    kg.auszahlen(0)   
    print("Oswald Meier überweist von Giro - auf Sparkonto")
    kg.ueberweisung(ks, 10000)    
    ks.auszahlen (3000)          
    print("Klaus Freund zahlt  auf sein Konto Nr.78200 ein")
    km.einzahlen(3000)
    print("Klaus Freund zahlt  von seinem Konto Nr.78200 aus")
    km.auszahlen (400) 
    km.ueberweisung(ks , 500)
    print("Überweisung Versuch von Konto nach Girokonto")
    km.ueberweisung(ks,468) 


    print( "------------------------------")

    # Zeige Kontodaten am Bildschirm    
    kg.zeige_konto()    
    ks.zeige_konto() 
    km.zeige_konto()


Benutzeravatar
Dennis89
User
Beiträge: 1526
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

wenn du von einer Klasse erbst dann hast du dadurch in der Kind-Klasse die Methoden der Eltern-Klasse. Du kannst die überschreiben, wenn sie was anderes machen sollen und das Sinn macht.
Siehe bei dir `ueberweisung`. `zeige_konto`ist etwas komisch wie du die Methode überschrieben hast. Das würde ich nicht machen, sondern die Methode der Eltern-Klasse aufrufen und den Zinssatz extra. Dann will man auf die Instanz zugreifen, also mit `self` und nicht auf das Objekt `Konto`. Aber der Teil fällt eh raus.

Wenn du das änders, dann kannst du die Unterscheidungsmerkmale der Kontentypen einfügen.


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

24.6.25
So, jetzt habe ich ein erstes Update hergestellt.
Allen Kram beseitigt,
Code lesbarer gemacht,
und versucht die Regeln von Python zu befolgen.
Ich sehe keinen Fehler mehr(??)
Das Programm ist beliebig erweiterbar.
Aber ein schönes Stück Arbeit.
Gute Zeit OSWALD

Code: Alles auswählen

class Konto(object): 
    """ Basis Konto Klasse """

    def __init__(self, inhaber, kontonummer, kontostand): 
        """ Konstruktor, Aufruf bei Instanzierung """                
        print( ".. Konto anlegen")
        self.Inhaber = inhaber 
        self.Kontonummer = kontonummer 
        self.Kontostand  = kontostand 
        self.zeige_konto()

    def einzahlen(self, betrag): 
        """ Mach eine Einzahlung """
        print (".. Einzahlen   : %i %5.1f" % (self.Kontonummer, betrag))
        self.Kontostand  += betrag 
 
    def auszahlen(self, betrag): 
        """ Mach eine Auszahlung """
        print( ".. Auszahlen   : %i %5.1f" % (self.Kontonummer, betrag))
        self.Kontostand  -= betrag 


##########Achtung die Methode ueberweisung wurde  aus Class Girokonto nach class Konto kopiert
    def ueberweisung(self, ziel, betrag): 
        """ Mach eine Ueberweisung """
        print( ".. Transfer    : %i %s %i %5.1f" % (self.Kontonummer, "->", ziel.Kontonummer, betrag))
        self.Kontostand  -= betrag 
        ziel.Kontostand  += betrag 

    def zeige_konto(self): 
        """ Zeige die Kontodaten am Bildschirm """
        print( ".. Konto       :", self.Inhaber)
        print( "   Kontonummer :", self.Kontonummer)
        print( "   Kontostand                    :", self.Kontostand  )

#############################
class Girokonto(Konto): 
    """ Giro Konto Klasse """

    def __init__(self, inhaber, kontonummer, kontostand, sollzinsen, habenzinsen): 
        """ Giro Konstruktor, Aufruf bei Instanzierung """                
        self.__Sollzinsen = sollzinsen
        self.__Habenzinsen = habenzinsen
        # initialisiere Konto
        Konto.__init__(self, inhaber, kontonummer, kontostand)
############# Hier liegr der Hund begraben
    def ueberweisung(self, ziel, betrag): 
        """ Mach eine Ueberweisung """
        print( ".. Transfer    : %i %s %i %5.1f" % (self.Kontonummer, "->", ziel.Kontonummer, betrag))
        self.Kontostand  -= betrag 
        ziel.Kontostand  += betrag 

##################################
class Sparkonto(Konto): 
    """ Sparbuch Konto Klasse """
    
    def __init__(self, inhaber, kontonummer, kontostand, zinssatz): 
        """ Spar Konstruktor, Aufruf bei Instanzierung """                
        self.Zinssatz = zinssatz
        # initialisiere des Kontos
        Konto.__init__(self, inhaber, kontonummer, kontostand)

    def zeige_konto(self): 
        """ Zeige die Kontodaten am Bildschirm, ueberschreibt Konto Funktion """
        Konto.zeige_konto(self) 
        print( ("   Zinssatz    :", self.Zinssatz ))
        

if __name__ == '__main__':
    
     
    
    print("                       Neues Konto erstellen  ")
    kgiro = Girokonto("Oswald Meier", 78340, 120, 0.05, 0.01) 
    kspar = Sparkonto("Oswald  Meier", 78341,  40.0, 0.03)  
    print()

    kgiro= Girokonto("Klaus Freund",78200, 50, 0.04, 0.01)
    kspar = Sparkonto("Klaus Freund", 78300, 150, 0.05)
               
    print( "                           Jetzt   Konten bearbeiten")
    
   
    print("=             Oswald Meier zahlt auf   sein  Girokonto  ein   :")
    kgiro.einzahlen(333333)
    print("                Oswald  Meier zahlt  auf   sein   Sparkonto ein    ")
    kspar.einzahlen(5555)    
    print("                Oswald Meier zahlt aus von Sparkonto")
    kgiro.auszahlen(0)   
    print("                Oswald Meier überweist von Giro - auf Sparkonto")
    kgiro.ueberweisung(kspar, 10000)    
    kspar.auszahlen (3000)          
    print()
    print("                         GIRO ktueller Kontostand  ")
    kgiro.zeige_konto()    
    print("                         SPAR  aktueller Kontostand  ")
    kspar.zeige_konto() 
    print()

    print( "                           Jetzt   Konten bearbeiten")
    print()
   
    print("Klaus Freund zahlt  auf sein Konto Nr.78300 ein")
    kgiro.einzahlen(3000)
    print("Klaus Freund zahlt  von seinem Konto Nr.78200 aus")
    kgiro.auszahlen (400) 
    kgiro.ueberweisung(kspar , 500)
    print("Überweisung Versuch von Konto nach Girokonto")
    kspar.ueberweisung(kgiro,468) 
    print()
    print("                         GIRO ktueller Kontostand  ")
    kgiro.zeige_konto()    
    print("                         SPAR  aktueller Kontostand  ")
    kspar.zeige_konto() 
    print()


Benutzeravatar
grubenfox
User
Beiträge: 606
Registriert: Freitag 2. Dezember 2022, 15:49

Der begrabene Hund (die Methode 'ueberweisung' in der Klasse GiroKonto) ist aktuell mindestens überflüssig und kann weg.
Und wenn man das Programm laufen lässt und sich die ausgegebenen Informationen anschaut, dann stellt man fest dass zum Teil die falschen Konten genutzt werden. Das wäre deutlicher erkennbar wenn man bei den Methoden 'einzahlen', 'auszahlen' und 'ueberweisung' nicht nur die Kontonummer ausgibt, sondern auch den Kontoinhaber.

Besser wäre wohl noch wenn die Methode 'ueberweisung' den Namen 'ueberweisen' hätte. Das passt dann besser zu 'einzahlen' und 'auszahlen'.

P.S. auch die Attribute einer Klasse sollten eigentlich klein geschrieben werden
OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

24.6.2025
@grubenfox danke für die guten Tips.
Ich bin selbst ganz verwirrt, weil ich zu viel Konten angesprochen habe, ohne besser zu kontrollieren. .
Neben der Kontonummer werde ich
auch die Inhaber anzeigen. Vielleicht schaffe ich auch noch die
Nullstellung aller Konten. Bevor ich den Polymorphismus angehen kann, muss ich noch Vieles klären.
'Nach update ist vor update' OSWALD
Benutzeravatar
Dennis89
User
Beiträge: 1526
Registriert: Freitag 11. Dezember 2020, 15:13

Um das mal etwas detaillierter zu beschreiben.
`Konto` muss nicht von `object` erben. Die ".. Konto anlegen" Ausgabe gehört nicht in die `__init__` das ist Programmablauf und sollte in die `main`-Funktion, das gilt auch für den `zeige_konto`-Aufruf. Namen werden klein mit Unterstrich geschrieben, Ausnahmen sind Konstanten die GANZ_GROSS und Klassen in PascalCase-Schreibweise.
Wenn eine Methode `einzahlen` heißt, dann sind die Doc-Strings überflüssig und auch die Kommentare. Ich verstehe das "Achtung...." nicht. Das verwirrt mich eher, als das es mir hilft.
Strings kann man schön leserlich mit f-Strings formatieren.
Wieso verwendest du 2 führende Unterstriche? Einer zeigt dem Leser an dass man auf die Werte von außerhalb nicht zugreifen soll.
Ich sehe keinen begrabenen Hund, nur die gleiche Methode wie schon in der Eltern-Klasse, die kann also weg.
In `SparKonto` finde ich das Überschreiben von `zeige_konto` nicht schön, weil man es nur um den Zinssatz ergänzt, dabei kann man den auch einfach so abfragen.
Alles unter `if __name__ == __main__:` gehört in eine `main`-Funktion. Aus ihr wird üblicherweise der Programmablauf gesteuert.
Ich habe mal die ganzen Leerzeichen noch entfernt, ich weiß nicht wie es dir geht, aber mich macht das verrückt.

Code: Alles auswählen

class Konto:
    def __init__(self, inhaber, kontonummer, kontostand):
        self.inhaber = inhaber
        self.kontonummer = kontonummer
        self.kontostand = kontostand

    def einzahlen(self, betrag):
        print(f"..Einzahlen: {self.kontonummer} {betrag:.1f}")
        self.kontostand += betrag

    def auszahlen(self, betrag):
        print(f"..Auszahlen: {self.kontonummer} {betrag:.1f}")
        self.kontostand -= betrag

    def ueberweisung(self, ziel, betrag):
        print(f"..Transfer: {self.kontonummer} -> {ziel.kontonummer} {betrag:.1f}")
        self.kontostand -= betrag
        ziel.kontostand += betrag

    def zeige_konto(self):
        print("..Konto:", self.inhaber)
        print("Kontonummer:", self.kontonummer)
        print("Kontostand:", self.kontostand)


class GiroKonto(Konto):
    def __init__(self, inhaber, kontonummer, kontostand, sollzinsen, habenzinsen):
        self.sollzinsen = sollzinsen
        self.habenzinsen = habenzinsen
        Konto.__init__(self, inhaber, kontonummer, kontostand)



class SparKonto(Konto):
    def __init__(self, inhaber, kontonummer, kontostand, zinssatz):
        self.zinssatz = zinssatz
        Konto.__init__(self, inhaber, kontonummer, kontostand)


def main():
    print("Neues Konto erstellen")
    oswald = GiroKonto("Oswald Meier", 78340, 120, 0.05, 0.01)
    oswald.zeige_konto()
    print()
    klaus = SparKonto("Klaus Freund", 78300, 150, 0.05)
    print("Jetzt Konten bearbeiten")
    print("=Oswald Meier zahlt auf sein Girokonto ein:")
    oswald.einzahlen(333333)
    print("Klaus zahlt auf sein Sparkonto ein")
    klaus.einzahlen(5555)
    print("Oswald Meier zahlt aus von Sparkonto")
    oswald.auszahlen(0)
    print("Oswald Meier überweist von Giro - auf Sparkonto")
    oswald.ueberweisung(klaus, 10000)
    klaus.auszahlen(3000)
    print()
    print("GIRO aktueller Kontostand")
    oswald.zeige_konto()
    print("SPAR aktueller Kontostand")
    klaus.zeige_konto()
    print(f"Zinssatz: {klaus.zinssatz}")
    print()
    print("Jetzt Konten bearbeiten")
    print()
    print("Oswald zahlt  auf sein Konto Nr.78340 ein")
    oswald.einzahlen(3000)
    print("Oswald zahlt von seinem Konto Nr.78340 aus")
    oswald.auszahlen(400)
    oswald.ueberweisung(klaus, 500)
    print("Überweisung Klaus an Oswald")
    klaus.ueberweisung(oswald, 468)
    print()
    print("GIRO ktueller Kontostand")
    oswald.zeige_konto()
    print("SPAR  aktueller Kontostand")
    klaus.zeige_konto()
    print()



if __name__ == '__main__':
    main()
Jetzt müsste man was sinnvolles mit den Vererbungen machen, den mit der Ausnahme vom anzeigen des Zinssatzes, könnte das alles ein `Konto` sein, denn das hat ja normal auch einen Zinssatz und dann wärst du wieder hier:

Code: Alles auswählen

class Konto:
    def __init__(self, inhaber, kontonummer, kontostand, zinssatz=None):
        self.inhaber = inhaber
        self.kontonummer = kontonummer
        self.kontostand = kontostand
        self.zinssatz = zinssatz

    def einzahlen(self, betrag):
        print(f"..Einzahlen: {self.kontonummer} {betrag:.1f}")
        self.kontostand += betrag

    def auszahlen(self, betrag):
        print(f"..Auszahlen: {self.kontonummer} {betrag:.1f}")
        self.kontostand -= betrag

    def ueberweisung(self, ziel, betrag):
        print(f"..Transfer: {self.kontonummer} -> {ziel.kontonummer} {betrag:.1f}")
        self.kontostand -= betrag
        ziel.kontostand += betrag

    def zeige_konto(self):
        print("..Konto:", self.inhaber)
        print("Kontonummer:", self.kontonummer)
        print("Kontostand:", self.kontostand)


def main():
    print("Neues Konto erstellen")
    oswald = Konto("Oswald Meier", 78340, 120)
    oswald.zeige_konto()
    print()
    klaus = Konto("Klaus Freund", 78300, 150, 0.05)
    print("Jetzt Konten bearbeiten")
    print("=Oswald Meier zahlt auf sein Girokonto ein:")
    oswald.einzahlen(333333)
    print("Klaus zahlt auf sein Sparkonto ein")
    klaus.einzahlen(5555)
    print("Oswald Meier zahlt aus von Sparkonto")
    oswald.auszahlen(0)
    print("Oswald Meier überweist von Giro - auf Sparkonto")
    oswald.ueberweisung(klaus, 10000)
    klaus.auszahlen(3000)
    print()
    print("GIRO aktueller Kontostand")
    oswald.zeige_konto()
    print("SPAR aktueller Kontostand")
    klaus.zeige_konto()
    print(f"Zinssatz: {klaus.zinssatz}")
    print()
    print("Jetzt Konten bearbeiten")
    print()
    print("Oswald zahlt  auf sein Konto Nr.78340 ein")
    oswald.einzahlen(3000)
    print("Oswald zahlt von seinem Konto Nr.78340 aus")
    oswald.auszahlen(400)
    oswald.ueberweisung(klaus, 500)
    print("Überweisung Klaus an Oswald")
    klaus.ueberweisung(oswald, 468)
    print()
    print("GIRO ktueller Kontostand")
    oswald.zeige_konto()
    print("SPAR  aktueller Kontostand")
    klaus.zeige_konto()
    print()



if __name__ == '__main__':
    main()
Deine Ausgaben und die verwirrten und falschen Kontenangaben habe ich auch aufgeräumt. Schau es dir mal in Ruhe an. Ich hoffe das hilft etwas weiter.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
snafu
User
Beiträge: 6854
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Man könnte die Basisfunktionalität für Geldbewegungen auch als transfer() abbilden, welcher Plus und Minus erlaubt und im Hintergrund jede Bewegung protokolliert. Spezialisierte Klassen würden dann konkrete Methoden implementieren. Von einem Sparkonto kann ich z. B. keine Überweisungen auf ein beliebiges Konto tätigen. Bei einem Wertpapierdepot habe ich ein Referenzkonto für die An- und Verkäufe und kann oft für eine Auszahlung an einer andere Bank nur ein vorab registriertes Konto benutzen. OOP kann da IMHO ziemlich gut benutzt werden, sobald man nicht mehr nur an der Oberfläche kratzt.

zeige_konto() ist übrigens eigentlich __str__(), nur dann eben als Rückgabe einer mit Newlines getrennten Zeichenkette. Die print()-Ausgaben innerhalb der Methoden würde ich nur fürs Debugging benutzen und später rausnehmen oder auskommentieren.
OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

26.6.25
Herzlichen Dank für die vielen Erläuterungen
und Tips, die ich alle umzusetzen versuche und z.T.
auch schon umsetzen konnte.
Allerdings habe ich festgestellt, dass ich quasi wieder ganz
von vorne beginnen muss.
Deshalb habe ich zunächst alles auf NULL gestellt, um
den Überblick nicht zu verlieren.
OSWALD

Code: Alles auswählen

class Konto(object): 
    """ Basis Konto Klasse """

    def __init__(self, inhaber, kontonummer, kontostand): 
        """ Konstruktor, Aufruf bei Instanzierung """                
        print( ".. Konto anlegen")
        self.Inhaber = inhaber 
        self.Kontonummer = kontonummer 
        self.Kontostand  = kontostand 
        self.zeige_konto()

    def einzahlen(self, betrag): 
        """ Mach eine Einzahlung """
        print (".. Einzahlen   : %i %5.1f" % (self.Kontonummer,       betrag))
        self.Kontostand  += betrag 
 
    def auszahlen(self, betrag): 
        """ Mach eine Auszahlung """
        print( ".. Auszahlen   : %i %5.1f" % (self.Kontonummer,       betrag))
        self.Kontostand  -= betrag 


    def ueberweisung(self, ziel, betrag): 
        """ Mach eine Ueberweisung """
        print( ".. Transfer    : %i %s %i %5.1f" % (self.Kontonummer, "->", ziel.Kontonummer,      betrag))
        self.Kontostand  -= betrag 
        ziel.Kontostand  += betrag 

    def zeige_konto(self): 
        """ Zeige die Kontodaten am Bildschirm """
        print( ".. Konto       :", self.Inhaber)
        print( "   Kontonummer :", self.Kontonummer)
        print( "   Kontostand                    :", self.Kontostand  )

#############################
class Girokonto(Konto): 
   

    def __init__(self, inhaber, kontonummer, kontostand, sollzinsen, habenzinsen): 
        """ Giro Konstruktor, Aufruf  Instanzierung """                
        self.__Sollzinsen = sollzinsen
        self.__Habenzinsen = habenzinsen
        # initialisiere Konto
        Konto.__init__(self, inhaber, kontonummer, kontostand)


 
    def ueberweisung(self, ziel, betrag): 
        """ Mach eine Ueberweisung """
        print( ".. Transfer    : %i %s %i %5.1f" % (self.Kontonummer, "->", ziel.Kontonummer,      betrag))
        self.Kontostand  -= betrag 
        ziel.Kontostand  += betrag 

############################## 
class Sparkonto(Konto): 
    """ Sparbuch Konto Klasse """
    
    def __init__(self, inhaber, kontonummer, kontostand, zinssatz): 
        """ Spar Konstruktor, Aufruf bei Instanzierung """                
        self.Zinssatz = zinssatz
        # initialisiere des Kontos
        Konto.__init__(self, inhaber, kontonummer, kontostand)

    def zeige_konto(self): 
        """ Zeige die Kontodaten am Bildschirm, ueberschreibt Konto Funktion """
        Konto.zeige_konto(self) 
        print( ("   Zinssatz    :", self.Zinssatz ))
####################################################        
#                       ALLE Konten  auf NUKL gesetzt
if __name__ == '__main__':
    
    print("                             Neues Konto erstellen  ")
    kgiro = Girokonto(" Oswald  Meier", 78340,   0.0, 0.0, 0.0) 
    kspar = Sparkonto("Oswald  Meier", 78341, 0.0, 0.0)  
    print()
    print("                               GIRO ktueller Kontostand  ")
    print(kgiro.zeige_konto()   ) 
    print("                                SPAR  aktueller Kontostand  ")
    kspar.zeige_konto() 
    print()

    kgiro  = Girokonto("Klaus Freund",78200, 0.0, 0.0, 0.0)
    kspar = Sparkonto("Klaus Freund",78300 ,0.0 , 0.00)
    print("=========================================")           
    print( "                           Jetzt   Konten bearbeiten")
    kgiro.ueberweisung(kspar,0.0)
   
    print("=             Oswald Meier zahlt auf   sein  Girokonto  ein   :")
    kgiro.einzahlen(0)
    print("                Oswald  Meier zahlt  auf   sein   Sparkonto ein    ")
    kspar.einzahlen(0)    
    print("                Oswald Meier überweist von Giro - auf Sparkonto")
    kgiro.ueberweisung(kspar, 0.0)    
    kspar.auszahlen (0.0)          
    print()
    print("     Oswald Meier                    GIRO aktueller Kontostand  ")
    print(kgiro.zeige_konto()   ) 
    print("                                                SPAR  aktueller Kontostand  ")
    kspar.zeige_konto() 
    print()
     
   
    print("Klaus Freund zahlt  auf sein Konto Nr.78300 ein")
    kgiro.einzahlen( 0)
    print("Klaus Freund zahlt  von seinem Konto Nr.78200 aus")
    kgiro.auszahlen (0) 
    kgiro.ueberweisung(kspar , 0.0)
     
    
    print("   Klaus Freund                      GIRO aktueller Kontostand  ")
    kgiro.zeige_konto()    
    print("                                                SPAR  aktueller Kontostand  ")
    kspar.zeige_konto() 
    print()

OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

4.7.2025Die objektorientierte Programmierung (OOP) basiert auf vier Hauptprinzipien:
Kapselung, Vererbung, Polymorphismus und Abstraktion.
Diese Prinzipien ermöglichen es, Code wieder verwendbar, flexibel und wartbar zu gestalten.

Ich habe mich intensiv mit Vererbung und Polymorphismus beschäftigt und versucht
die komplexe Materie ein bisschen besser zu verstehen.
Kapselung und Abstraktion folgen später.
Dazu kam mir ein Programm gelegen, das ich hier vorstellen will:
Auf den ersten Blick nicht gerade aufregend, aber nach und nach
zeigte sich , dass es eine Menge über OOP bietet.
Es hat sich gelohnt.
Gute Zeit OSWALD

Code: Alles auswählen


 
class Container:
    def __init__(self, volume):
        # volume in ml
        self._volume = volume
        # start out with empty container
        self._contents = {}
    
    def __repr__(self):
        """
        Textual representation of container
        """
        repr = f"{self._volume} ml Container with contents {self._contents}"
        return repr
    
    def volume(self):
        """
        Volume getter
        """
        return self._volume
    
    def is_empty(self):
        """
        Container is empty if it has no contents
        """
        return self._contents == {}
    
    def is_full(self):
        """
        Container is full if volume of contents equals capacity
        """
        return self.volume_filled() == self.volume()
    
    def volume_filled(self):
        """
        Calculate sum of volumes of contents
        """
        return sum(self._contents.values())
    
    def volume_available(self):
        """
        Calculate available volume
        """
        return self.volume() - self.volume_filled()
    
    def empty(self):
        """
        Empty the container, returning its contents
        """
        contents = self._contents.copy()
        self._contents.clear()
        return contents
    
    def _add(self, substance, volume):
        """
        Internal method to add a new substance / add more of an existing substance
        """
        # update volume of existing substance
        if substance in self._contents:
            self._contents[substance] += volume
        # or add new substance
        else:
            self._contents[substance] = volume
    
    def add(self, substance, volume):
        """
        Public method to add a substance, possibly returning left over
        """
        if self.is_full():
            raise Exception("Cannot add to full container")
        # we can fit all of the substance
        if self.volume_filled() + volume <= self.volume():
            self._add(substance, volume)
            return self
        # we can fit part of the substance, returning the left over
        else:
            leftover = volume - self.volume_available()
            self._add(substance, volume - leftover)
            return {substance: leftover}
    
    def fill(self, substance):
        """
        Fill the container with a substance
        """
        if self.is_full():
            raise Exception("Cannot fill full container")
        self._add(substance, self.volume_available())
        return self
    
    def pour_into(self, other_container):
        """
        Transfer contents of container to another container
        """
        if other_container.volume_available() < self.volume_filled():
            raise Exception("Not enough space")
        # get the contents by emptying container
        contents = self.empty()
        # add contents to other container
        for substance, volume in contents.items():
            other_container.add(substance, volume)
        return other_container
    
    def __add__(self, other_container):
        """
        Implement addition for containers:
        `container_a + container_b` <=> `container_b.pour_into(container_a)`
        """
        other_container.pour_into(self)
        return self
glass = Container(300)
glass.fill('Water')
assert glass.is_full()
 
contents = glass.empty()
assert contents == {'Water': 300}
assert glass.is_empty()
 
pitcher = Container(1500)
bottle = Container(700)
carton = Container(500)
# fill ingredients
bottle.fill('Red wine')
carton.fill('Orange juice')
 
# pour ingredients into pitcher
pitcher += bottle                       # pitcher ist Krig zum Ausschenken
pitcher += carton
# check that everything worked
assert pitcher.volume_filled() == 1200
assert bottle.is_empty() and carton.is_empty()
 

 
    
 

#Vererbung
 
 
class Sealable:
    """
    Implementation needs to:
    - initialize `self._seal`
    """
    def is_sealed(self):
        return self._seal is not None
    
    def is_open(self):
        return not self.is_sealed()
    
    def is_closed(self):
        return not self.is_open()
    
    def open(self):
        """
        Opening removes and returns the seal
        """
        seal = self._seal
        self._seal = None
        return seal
    
    def seal_with(self, seal):
        """
        Closing attaches the seal and returns the Sealable
        """
        self._seal = seal
        return self
 
class SealableContainer(Container, Sealable):
    """
    Start out with empty, open container
    """
    def __init__(self, volume, contents = {}, seal = None):
        # initialize `Container`
        super().__init__(volume)
        # initialize contents
        self._contents = contents
        # initialize `self._seal`
        self._seal = seal
    
    def __repr__(self):
        """
        Append 'open' / 'closed' to textual container representation
        """
        state = "Open" if self.is_open() else "Closed"
        repr = f"{state} {super().__repr__()}"
        return repr
    
    def empty(self):
        """
        Only open container can be emptied
        """
        if self.is_open():
            return super().empty()
        else:
            raise Exception("Cannot empty sealed container")
    
    def _add(self, substance, volume):
        """
        Only open container can have its contents modified
        """
        if self.is_open():
            super()._add(substance, volume)
        else:
            super()._add(substance, volume+volume)
        
glass = Container(530)
cola_bottle = SealableContainer(530, contents = {'Cola': 250}, seal = 'Bottlecap')  # ='Kron-verschluss'
shot_glass = Container(140)
shot_glass.add('Rum', 20)
shot_glass.add('Sirup',50)
shot_glass.add('Gin',30)
shot_glass.add('Eis',100)

#                      Wir geben etwas Eis in da Glas und fügen den Rum hinzu.
#                      Da die Cola-Flasche verschlossen ist, öffnen wir sie zunächst und gießen dann den Inhalt in das Glas:

glass.add('Ice', 50)
# add rum
glass += shot_glass
# open cola bottle
if cola_bottle.is_closed():
    cola_bottle.open()
# pour cola into glass
glass += cola_bottle
print(glass)
    



OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

r 4.7.2025
Und hier noch zwei prägnante Beispiele für
Polymorphismus
OSWALD

Code: Alles auswählen


lass TestPolymorphismus:
    def add(self,a,b,c=None):
        if c ==None:
            sum  = a+b
            return sum
        else:
            sum = a+b+c
            return sum

obj = TestPolymorphismus()
print(obj.add(1,2))
print(obj.add(1,2,3))


#####################
class Vektor: 
    """ 2D Vektor Klasse """

    def __init__(self, x, y):              
        self.x = x 
        self.y = y 

    def __add__(self, other): 
        """ Ueberladener '+' Operator """
        return Vektor( self.x+other.x, self.y+other.y )

    def __str__(self): 
        """ Ueberladene print Funktion """
        return f"[{self.x} {self.y}]" 
        

if __name__ == '__main__':
    
    print("\nBeispiel Polymorphismus")
    
    # Erzeuge zwei Vektor Objekte
    v1 = Vektor(3,4)
    v2 = Vektor(1,2) 
    v3 = Vektor(7,10)
    # Addiere 2 Vektoren
    vs = v1 + v2 
              
    # Ausgabe des neuen Vektors    
    print('vs =', vs)
    print(v3) 



Benutzeravatar
__blackjack__
User
Beiträge: 14019
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@OSWALD: Was genau ist denn da jetzt der Polymorphismus? Gezeigt wird da nicht wirklich etwas.

Wobei das erste Beispiel ja nicht mal ein Beispiel für eine Klasse ist, denn ein Objekt ohne Zustand mit nur einer “Methode“ ist einfach nur eine recht umständlich geschriebene Funktion.

Edit: 1. Beispiel ohne ”Klasse”:

Code: Alles auswählen

def add(a, b, c=None):
    return a + b if c is None else a + b + c


print(add(1, 2))
print(add(1, 2, 3))
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
OSWALD
User
Beiträge: 582
Registriert: Freitag 18. März 2022, 17:32

4.7.2025
@ blackjack
Ich habe deshalb die beiden Programmbeispiele gegenüber gestellt.
Und schon taucht das nächste Problem auf.
----Unterschied Vererbung und Komposition von Klassen -----
Ich darf mich nur nicht entmutigen lassen.Ich dafür ch ein Programmbeispiel,
muss das aber noch verstehen. Auf jeden Fall spannend.
OSWALD
Antworten