Anfänger in OOP hat folgendes Problem

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.
Antworten
breathe_easy
User
Beiträge: 58
Registriert: Sonntag 29. Juli 2007, 18:34

Code: Alles auswählen

#! /usr/bin/python
# -*- coding: utf-8 -*-

class Bruch ():

        def _init_ (self):
                self.Zaehler = int(raw_input("Bitte geben Sie den Zaehler ein; "))
                self.Nenner = int(raw_input("Bitte geben Sie den Nenner ein: "))
                print "Ein Bruch ist geboren: "

        def get_Nenner(self):
                Nenner = self.Nenner
                return Nenner

        def get_Zaehler(self):
                Zaehler = self.Zaehler
                return Zaehler

        def Multiplikation (self, neuer_Bruch):
                neuer_zaehler = self.Zaehler * neuer_Bruch.get_Zaehler()
                neuer_Nenner = self.Nenner  * neuer_Bruch.get_Nenner()


Bruch1 = Bruch ()
Bruch2 = Bruch ()

Bruch1.Multiplikation(Bruch2)
x = raw_input()




Traceback (most recent call last):
  File "D:\python programme\Bruch.py", line 27, in <module>
    Bruch1.Multiplikation(Bruch2)
  File "D:\python programme\Bruch.py", line 20, in Multiplikation
    neuer_zaehler = self.Zaehler * neuer_Bruch.get_Zaehler()
AttributeError: Bruch instance has no attribute 'Zaehler'
Wieso hat das neue Objekt keinen Zaehler? Und was ganz anderes kann mir jemand eine Entwicklungsumgebung unter Linux empfehlen incl. Debugger?
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Mäh... Warum raw_input und keine Argumente im Konstruktor? Wieso get_zaehler und nicht direkt auf zaehler zugreifen? Wieso ein Leerzeichen zwischen den Definitionen und den runden Klammern? Wieso zuerst an einen Namen binden, der nur im Funktionskörper vorhanden ist und diesen dann zurückgeben anstatt direkt return self.nenner? Wieso bindet multiplikation die beiden sachen an Namen, die überhaupt gar keine Instanzvariablen sind?

Das Konzept is'n bissel... komisch. Vielleicht nochmal überdenken! Mal ein Ansatz:

Code: Alles auswählen

class Fraction(object):
    def __init__(self, denominator, numerator):
        self.denominator = denominator
        self.numerator = numerator
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Hallo,

schreib mal die __init__-Methode mit zwei führenden und abschließenden Unterstrichen. Das gilt übrigens für alle "eingebauten" Klassenmethoden in Python.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das habe ich ihm in einem anderen Thread auch schon alles erzählt, daher vielleicht mal ein Vorschlag:

Code: Alles auswählen

class Fractional(object): 
    def __init__(self, numerator, denominator): 
        self.numerator = numerator
        self.denominator = denominator
    
    def __mul__(self, other): 
        return Fractional(self.numerator * other.numerator,
                          self.denominator * other.denominator)
    
    def __str__(self):
        return "%d/%d" % (self.numerator, self.denominator)


if __name__ == "__main__":
    b1 = Fractional(1, 3)
    b2 = Fractional(2, 4)
    
    print b1
    print b2
    print b1*b2
breathe_easy
User
Beiträge: 58
Registriert: Sonntag 29. Juli 2007, 18:34

Hi BlackVivi,
will mich nicht rausreden aber habe erst gestern mit OOP angefangen. Leerzeichen war ein Versehen.
Wieso zuerst an einen Namen binden, der nur im Funktionskörper vorhanden ist und diesen dann zurückgeben anstatt direkt return self.nenner? Wieso bindet multiplikation die beiden sachen an Namen, die überhaupt gar keine Instanzvariablen sind?
Verstehe ich nicht! Kannst du mir das bitte mal neu erklären?
breathe_easy
User
Beiträge: 58
Registriert: Sonntag 29. Juli 2007, 18:34

Hi EyDu,
danke für deinen Vorschlag, aber ich bräuchte eine Antwort auf meine Frage.
Dein Code ist sicher besser aber ich würde gerne verstehen was ich, von den Stylefehlern mal abgesehen, falsch gemacht habe.
Trotzdem Danke für deine Antwort.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

breathe_easy hat geschrieben:Verstehe ich nicht! Kannst du mir das bitte mal neu erklären?
Du kannst statt

Code: Alles auswählen

def get_Nenner(self):
    Nenner = self.Nenner 
    return Nenner
auch

Code: Alles auswählen

def get_Nenner(self):
    return self.Nenner 
schreiben.

Dann kannst du aber aber auch gleich die Methode sparen und direkt auf das Attribut von außen zugreifen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

breathe_easy hat geschrieben:Dein Code ist sicher besser aber ich würde gerne verstehen was ich, von den Stylefehlern mal abgesehen, falsch gemacht habe.
Es ist im Prinzip genau das, was BlackVivi schon angemerkt hat.

Dein Problem ist wahrscheinlich noch die Abstraktion und der Trennung. Du vermischt die Logik der Bruchrechnung mit der Eingabe der Brüche. Das das unpraktisch ist wirst du spätestens dann merken, wenn du mit den Brüchen rechnen willst OHNE diese eingeben zu wollen.

Dann gibt die Multiplikation bei mir auch als Ergebnis einen Bruch zurück, so dass du damit weiterrechnen kannst. Wenn du zwei Brüche multiplizierst, kommt, wie man es erwartet, auch wieder ein Bruch raus.
breathe_easy
User
Beiträge: 58
Registriert: Sonntag 29. Juli 2007, 18:34

o.k. trotzdem noch ein paar unklare Punkte:

Code: Alles auswählen

    def __str__(self):
        return "%d/%d" % (self.numerator, self.denominator)
verstehe ich gar nicht! Was ist %d in diesem Fall?
und

Code: Alles auswählen

if __name__ == "__main__":
    b1 = Fractional(1, 3)
    b2 = Fractional(2, 4)
lässt mich gedanklich auch im Regen stehen! Für eine kurze Erklärung wäre ich echt dankbar.

breathe_easy
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Wieso zuerst an einen Namen binden, der nur im Funktionskörper vorhanden ist und diesen dann zurückgeben anstatt direkt return self.nenner?

Code: Alles auswählen

        def get_Nenner(self):
                Nenner = self.Nenner
                return Nenner

        def get_Zaehler(self):
                Zaehler = self.Zaehler
                return Zaehler
Warum das statt diesem:

Code: Alles auswählen

        def get_Nenner(self):
                return self.Nenner

        def get_Zaehler(self):
                return self.Zaehler
Aber getter und setter brauchst du nicht. Du kannst jederzeit mit instanz.instanzvariable drauf zugreifen. Du brauchst sie erst wenn du Daten vor dem binden überprüfen musst und selbst da gibt es bei Python wohl elegantere Lösungen.
Wieso bindet multiplikation die beiden sachen an Namen, die überhaupt gar keine Instanzvariablen sind?
Spreche von dieser Funktion

Code: Alles auswählen

        def Multiplikation (self, neuer_Bruch):
                neuer_zaehler = self.Zaehler * neuer_Bruch.get_Zaehler()
                neuer_Nenner = self.Nenner  * neuer_Bruch.get_Nenner()
Was sollen neuer_zaehler und neuer_nenner darstellen? Und was passiert mit ihnen? Sie werden erstellt, schön und gut! Aber dann?... Sie sind, nachdem der Funktionkörper beendet wurde, weg, weil sie nur in diesem "Pool" waren. Du musst sie schon an die Instanz mit self. binden. Also...

Code: Alles auswählen

        def Multiplikation (self, neuer_Bruch):
                self.Zaehler = self.Zaehler * neuer_Bruch.get_Zaehler()
                self.Nenner = self.Nenner  * neuer_Bruch.get_Nenner()
wäre sinnvoller. Aber die Frage ist halt... das ganze Konzept ist nicht so toll.

Du musst dir das Objekt "Bruch" mal vorstellen. Was besitzt es, was kann es? Was _braucht_ es? Es braucht einen Zähler und einen Nenner, mehr besitzt er ja nicht. Er hat eine Darstellung mit zähler/nenner, man kann mit ihnen die Rechenoperationen durchführen. 2 Brüche miteinander und auch normale Zahlen und Brüche.

Also das Konzept sagt uns es gibt Bruch mit den Instanzvariablen nenner und zähler. Diese beiden werden immer benötigt, haben also auch Standardwerte. So haben wir doch schonmal den Kopf des Objektes

Code: Alles auswählen

class Bruch(object):
    def __init__(self, zaehler=0, nenner=0):
        self.zaehler = zaehler
        self.nenner = nenner
So bau ich mir meine Objekte zumindest auf... Was hab ich, was will ich, was soll passieren. Und halt dich am besten an den Styleguide... er führt zu gleichbleibenden Code.

funktionsnamen_klein_und_unterstriche
KlassenGrossUndZusammen
variablen_auch_klein_und_unterstriche

Stets um ein = Leerzeichen, außer bei Standardwerten von Funktionen. Mach deine Zeilen nich zu lang, kannst ja jederzeit umbrechen.

Is so das wichtigste erstmal.
breathe_easy
User
Beiträge: 58
Registriert: Sonntag 29. Juli 2007, 18:34

Danke BlackVivi!
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Wobei ein Nenner=0 etwas problematisch wäre ;)
Antworten