Überladung von Operatoren

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.
Gast

Überladung von Operatoren

Beitragvon Gast » Mittwoch 9. Juli 2003, 01:57

hm, was bedeutet das eigentlich genau?

was würde nicht gehen, wenn diese überladung nicht möglich wäre?

und vor allem: warum findet eine überladung bei der verwendung des __init__ konstruktors statt, wie vielfach geschrieben wird, oder wann findet sie konkret statt, oder findet sie tatsächlich immer statt???

ich bin etwas verwirrt :shock:

mfg

roland
joerg
User
Beiträge: 188
Registriert: Samstag 17. August 2002, 17:48
Wohnort: Berlin
Kontaktdaten:

Beitragvon joerg » Mittwoch 9. Juli 2003, 08:34

Überladen von Methoden heißt in dem Fall 'Überschreiben der entsprechendenden Elternmethoden'. Operatorüberladung ist das Überschreiben spezieller Methoden. Diese speziellen Methoden werden gerifen, wenn ein Operator auftritt.

Ich kann mir z.B. beliebige komplexe Objekte basteln, und mit Operatorüberladung definieren,w as passieren soll, wenn ich z.B. zwei dieser Objekte mittels '+' addiere.

Ich kann also dem Operator '+' in Verbindung mit meinen Objekten einen eigenen, von mir bestimmten Sinn geben.

Natürlich geht das auch für andere Operatoren.

Jörg
Gast

ja schon aber....

Beitragvon Gast » Mittwoch 9. Juli 2003, 10:56

kannst du mir das mal konkret darstellen?

heisst das weil ich z.b auch zwei strings mit + verbinden kann?

und was hat es mit der überladung des konstruktors auf sich?
joerg
User
Beiträge: 188
Registriert: Samstag 17. August 2002, 17:48
Wohnort: Berlin
Kontaktdaten:

Re: ja schon aber....

Beitragvon joerg » Mittwoch 9. Juli 2003, 11:42

rolgal hat geschrieben:kannst du mir das mal konkret darstellen?

heisst das weil ich z.b auch zwei strings mit + verbinden kann?

und was hat es mit der überladung des konstruktors auf sich?


Der Konstruktor (__init__) kann wie jede andere Methode auch überladen/überschrieben werden. Meist will man aber, daß der Elternkonstruktor trotzdem ausgeführt wird, und der Kindkonstruktor nur zusätzlich. Dann muß man den Elternkonstruktor explizit innerhalb des Kindkonstruktors aufrufen:

Code: Alles auswählen

class A:
  def __init__(self, a):
    self.a = a

class B(A):
  def __init__(self, a, b):
    A.__init__(self, a)
    self.b = b


Zum Überladen von Operatoren: Du willst eine Klasse haben, die einen einheitenbehafteten Zahlenwert darstellt, also einen float und eine Einheit, z.B. als String.

Nun wäre es doch praktisch, wenn Du mit Instanzen dieser Klasse ganz normale Operationen durchführen kannst, wobei Einheiten automatisch konvertiert werden sollen. Also definierst Du für Deine Klasse eine Methode '__add__'.

Diese Methode bekommt als Argumente sich selbst und den Operationspartner. Innerhalb der Methode kannst Du nun den Typ auswerten: Instanz + Instanz geht, Instanz plus float oder int geht auch, sonst geht es nicht. Der Returnwert ist das Ergebnis der Addition, also eine neue Instanz deiner Klasse.

Ab sofort kannst Du einfach "A+B" schreiben, wobei A und B Instanzen deiner ZahlMitEinheit-Klasse ist. Python erkennt,
daß es diese Methode benutzen soll, um diese Instanzen zu addieren.

Genauso gehts Du noch für Subtraktion, Multiplikation ... usw. vor.

Natürlich kann man damit auch Blödsinn machen. Also eine Klasse definieren, die sich wie ein Integer verhält, aber bei '-' immer addiert statt subtrahiert... ;-)

Ich hoffe, das war jetzt etwas klarer.

Jörg
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Beitragvon Milan » Mittwoch 9. Juli 2003, 12:50

Ich komm mir jetzt wieder nen bissl dumm vor, wenn ich "nur" einen Link zu einem älterem Thema präsentiere, aber vielleicht erkennst du es an den Beispielen dort noch besser ;)
Gast

jaja, äh ich weiss....

Beitragvon Gast » Mittwoch 9. Juli 2003, 13:32

ich habe das schon mal gefragt.....

ehrlich gesagt versteh ich es nur bedingt.

aber eigentlich auch egal, meistens erschliessen sich die sachen, wenn man sie wirklich braucht.

das mit dem konstruktor habe ich hoffentlich verstanden: er wird nur dann überladen, wenn in der subklasse der konstruktor der elternklasse aufgerufen wird, oder?

mfg

roland
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Beitragvon Milan » Mittwoch 9. Juli 2003, 14:32

Ich glaube hier verwechselst du zwei verschiedene Sachen, oder? Methoden (wozu auch der Konstruktor gehöhrt) werden beim Ableiten von anderen Klassen vererbt, es sei denn sie werden überdefiniert (also quasi neu geschrieben). Wenn du das mit dem konstruktor tust, kannst du den Konstruktor der alten Klasse an deiner neuen Klasse rufen. Bsp:

Code: Alles auswählen

class a:
    def __init__(self,arg1):
        self.arg1=arg1

class b(a):    #Ableiten von a
    def __init__(self,ar1,arg2):
        a.__init__(self,arg1)    #hier wird self übergeben! --> der Konstruktor (init) von a wird an b (momentan self) gerufen
        self.arg2=arg2
...
>>> x=b(1,2)
>>> b.arg1,b.arg2
(1 , 2)


Das andere ist das überladen von Operatoren. Hier definierst du was beim addieren, subtrahieren und allen möglichen anderen Operationen mit deiner Klasse passieren soll.
Zuletzt geändert von Milan am Mittwoch 9. Juli 2003, 14:33, insgesamt 1-mal geändert.
joerg
User
Beiträge: 188
Registriert: Samstag 17. August 2002, 17:48
Wohnort: Berlin
Kontaktdaten:

Re: jaja, äh ich weiss....

Beitragvon joerg » Mittwoch 9. Juli 2003, 14:32

rolgal hat geschrieben:das mit dem konstruktor habe ich hoffentlich verstanden: er wird nur dann überladen, wenn in der subklasse der konstruktor der elternklasse aufgerufen wird, oder?


Nein. Überladen heißt: Überschreiben. Und überschrieben wird eine Methode der Elternklasse, wenn ich in der Kindklasse eine gleichnamige Methode definiere. Damit wird, wenn ich die Methode einer Instanz der Kindklasse rufe, die Methode der Kindklasse genommen, und nicht mehr die der Elternklasse.

Gerade bei Konstruktor-Methoden ist dieses Verhalten jedoch oft (aber nicht immer) unerwünscht. Wir wollen ja meistens, daß die Konstruktoren aller Klassen ausgeführt werden, da sie meistens irgendwelche wichtigen Initialisierungen durchführen.

Also müssen wir im Kindklassen-Konstruktor, der ja den Konstruktor der Elternklasse übercshrieben hat, den Konstruktor der Elternklasse explizit aufrufen, damit die dort enthaltenen Anweisungena auch wirklich ausgeführt werden.

Jörg
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Mittwoch 9. Juli 2003, 14:40

Hallo Roland,
rolgal hat geschrieben:das mit dem konstruktor habe ich hoffentlich verstanden: er wird nur dann überladen, wenn in der subklasse der konstruktor der elternklasse aufgerufen wird, oder?


nein, umgekehrt, wenn der Kunstruktor also die Methode __init__ nicht überlagden wird, wird immer, falls vorhanden der Konstruktor der Elternklasse ausgeführt.

Beispiel:

Code: Alles auswählen

class A:
    def __init__(self, a): # Konstruktor für A
        self.a = a
        print "Der Konstruktor von A wurde ausgeführt!"

class B(A):
    def __init__(self, a, b): # Konstruktor für B
        A.__init__(self, a) # Konstruktor für A aufrufen
        self.b = b
        print "Der Konstruktor von B wurde ausgeführt!"

class C(A): # hier gibts keinen eigenen Konstruktor
    def Hallo(self):
        print self.a

class D(A):
    def __init__(self, d): # Konstruktor für D
        self.d = d
        print "Der Konstruktor von D wurde ausgeführt!"
>>> a = A(1)
Der Konstruktor von A wurde ausgeführt!
>>> b = B(1,2)
Der Konstruktor von A wurde ausgeführt!
Der Konstruktor von B wurde ausgeführt!
>>> c = C(3)
Der Konstruktor von A wurde ausgeführt!
>>> d = D(4)
Der Konstruktor von D wurde ausgeführt!
>>>


A ist die Basisklasse.
Bei B wird der Konstruktor überladen da mehr Parameter verwendung finden und der Konstruktor der Basisklasse, mit den für diese notwendigen Parametern aufgerufen.
Bei C wird der Konstruktor der Basisklasse nicht überladen, daher er wird von A geerbt und beim instanziieren der Klasse ausgeführt!
Bei D wird der Konstuktor überladen, aber nicht der Konstruktor der Basisklasse A aufgerufen. Dies ist nicht zu empfehlen, da bei einer Änderung des Konstruktors der Basisklasse diese Änderung in D nicht bemerkt wird und so zu seltsamen Verhalten der Instanzen führen kann.

Also merke, wenn keine zusätzlichen Initialisierungen in der Kindklasse nötig sind, einfach den Konstruktor __init__ nicht überladen, sind zusätzliche Parameter und Initialisierungen nötig, so überlade den Konstruktor und führe an geeigneter Stelle den Konstruktor der Basisklasse aus.
Jede Basisklasse, also eine Klasse die nicht von einer anderen Klasse abgeleitet wird sollte, auch wenn (noch) keine Initialisierungen nötig sind einen __init__ Konstruktor definieren. So sind bei späteren Erweiterungen der Basisklasse keine Überaschungen bei von dieser abgeleiteten Kindklassen zu erwarten.


Gruß

Dookie
Gast

danke an alle

Beitragvon Gast » Mittwoch 9. Juli 2003, 16:46

:)

also, das scheint schon eine nicht ganz einfache sache zu sein. so wie oop allgemein. das prinzip ist ja relativ schnell klar, das aber effizient und sinnvoll anzuwenden scheint mir eine andere sache

wie meinte schon mal jmd. anderer zu dem thema an anderer stelle: ganz klar ist es noch nicht, aber es dämmert zumindest.

ich gehe das mal alles durch und erkläre es euch dann:-))))))))))))))))))))))

mfg

roland

Wer ist online?

Mitglieder in diesem Forum: /me, Bing [Bot]