Objektorientierte Programmierung in Python

Beispiel: Schildkroete

import math
class Schildkroete:
 
    # Konstruktor
    def __init__(self, zeichenbrett):
        self.__x = 100
        self.__y = 100
        self.__winkel = 0
        self.__bogenmass = 0
    # Methoden (self muss immer der erste Parameter sein)
    def setX (self, x):
        self.__x=x
    def getX (self):
        return self.__x
    def setY (self, y):
        self.__y=y
    def getY (self):
        return self.__y
    def setWinkel (self,w):
        self.__winkel=w
        self.__bogenmass = math.pi * 2 * self.__winkel / 360
    def getWinkel (self):
        return this.__winkel
 
    def gehe(self, n):
        dx = n * math.sin (self.__bogenmass)
        dy = n * math.cos (self.__bogenmass)
        xNeu = self.__x + dx
        yNeu = self.__y + dy
        zeichenbrett.create_line(self.__x, self.__y, xNeu, yNeu)
        self.__x = xNeu
        self.__y = yNeu
    def dreheLinks(self, w):
        self.__winkel += w + 360
        self.__winkel = self.__winkel % 360
        self.__bogenmass = math.pi * self.__winkel / 360 * 2
    def dreheRechts(self, w):
        self.__winkel -= w + 360
        self.__winkel = self.__winkel % 360
        self.__bogenmass = math.pi * self.__winkel / 360 * 2
 
 
# Import der Tkinter-Bibliotek, mit deren Hilfe gezeichnet wird
from tkinter import *
 
# Fensteranwendung mit Namen fester erstellen
fenster = Tk()
 
# Groesse des Fensters
breite = 600
hoehe = 600
rand = 5
 
# erstellt die Komponente , auf der man zeichnen kann
zeichenbrett = Canvas (fenster, width=breite, height=hoehe)
 
# zeichnet das Haus des Nikolaus
 
 
# platziert die erzeugten Elemente (Canvas, Button, Textfelder, ...) im Fenster
zeichenbrett.pack()
 
# Endlosschleife:
fenster.mainloop()

Die objektorientierte Programmierung in Python wird an einem Beispiel demonstriert, das dem Buch „Python“ aus dem Verlag Galileo Computing entnommen ist. Ziel ist es, ein sehr einfaches Programm für eine Bank zu entwickeln, mit dessen Hilfe Konten verwaltet sowie Überweisungen und Ein- bzw. Auszahlungen vorgenommen werden können. Dies geschieht mit Objekten der selbst definierten Klasse „Konto“.

Klassen

Zur Definition einer Klasse in Python dient das Schlüsselwort class, dem der Name der Klasse folgt. Der Zusatz (object) wird im Abschnitt „Vererbung“ erklärt.

class Konto(object):
    ...
    ...

Ein neues Objekt (also eine Instanz) der Klasse wird durch Angabe des Klassennamens mit einem Klammerpaar erreicht:

k1 = Konto()

Methoden

Die Definition einer Methode unterscheidet sich nur geringfügig von der Definition einer Funktion: Sie steht innerhalb des von class eingeleiteten Blocks und enthält als ersten Parameter eine Referenz auf die Instanz, über die sie aufgerufen wird. In diesem Beispiel ist das das Objekt selbst, deshalb heißt diese Referenz self.

class Konto(object):
 
    def ueberweisung(self, ziel, betrag):
        ...
 
    def einzahlen(self, betrag):
        ...
 
    def auszahlen(self, betrag):
        ...

Attribute

Attribute sind die Eigenschaften eines Objektes. Im Beispiel der Klasse „Konto“ sind die Attribute: Kontoinhaber, Kontonummer, Kontostand, maximaler Tagesumsatz, heutiger Tagesumsatz.

Konstruktor

Der Konstruktor ist die Methode, die genau einmal bei der Erzeugung des Objektes aufgerufen wird. Da es die Aufgabe des Konstruktors ist, das Objekt in einen definierten Ausgangzustand zu verstetzen, sollten hier auch die Attribute definiert werden. Konstruktoren haben in Python immer den Namen init (zwei Unterstriche vorher und nachher).

class Konto(object):
 
    def __init__(self, inhaber, kontonummer, kontostand, max_tagesumsatz=1500):
        self.Inhaber = inhaber
        self.Kontonummer = kontonummer
        self.Kontostand = kontostand
        self.MaxTagesumsatz = max_tagesumsatz
        self.UmsatzHeute = 0
 
    # hier kommen die restlichen Methoden hin

Destruktor

Der Destruktor ist die Methode zum Vernichten eines Objektes (in unserem Beispiel: Kontoauflösung). Er hört auf den Namen del.

class Konto(object):
 
    # hier kommt der Konstruktor hin
 
    def __del__(self):
        print "Das Konto wurde aufgelöst"
 
    # hier kommen die restlichen Methoden hin

Kapselung

Attribute und Methoden, die von außen nicht sichtbar sein sollen, können so gekennzeichnet werden, dass nur die Klasse selbst darauf zugreifen kann. Die Manipulation der Objekte erfolgt dann ausschließlich über die von außen sichtbaren Methoden und Attribute.
In Python wird über den Namen eines Attributes oder einer Methode festgelegt, ob es von außen sichtbar (public) oder unsichtbar (private) ist. Private Attribute und Methoden beginnen mit zwei Unterstrichen.

Das Beispiel wird so geändert, dass die Attribute nicht direkt geändert werden können:

class Konto(object):
 
    def __init__(self, inhaber, kontonummer, kontostand, max_tagesumsatz=1500):
        self.__Inhaber = inhaber
        self.__Kontonummer = kontonummer
        self.__Kontostand = kontostand
        self.__MaxTagesumsatz = max_tagesumsatz
        self.__UmsatzHeute = 0
 
    # hier kommen die restlichen Methoden hin

Getter und Setter

Sind die Attribute eines Objektes nicht mehr sichtbar, benötigt man von außen zugängliche Methoden, um Attribute auszulesen (Get-Methode oder Getter) oder zu schreiben (Set-Methode oder Setter).
In unserem Beispiel wird ein Getter für den Kontostand und das Tageslimit eingefügt. Außerdem schreiben wir einen Setter für das Tageslimit, der gleichzeitig überprüft, ob der übergebene Wert zulässig ist:

class Konto(object):
 
    # hier kommt der Konstruktor hin
 
    # Getter für den Kontostand
    def kontostand(self):
        return self.__Kontostand
 
    # Getter für das Umsatzlimit
    def maxTagesumsatz(self):
        return self.__MaxTagesumsatz
 
    # Setter für das Umsatzlimit   
    def setMaxTagesumsatz(self, neues_limit):
        if neues_limit > 0:
            self.__MaxTagesumsatz = neues_limit
            return True
        else:
            return False
 
    # hier kommen die restlichen Methoden hin

Versteckte Getter und Setter

In Python ist es möglich, die Get- und Set-Methoden zu „verstecken“. Nach außen sieht es so aus, als könnten die Attribute direkt gelesen oder geschrieben werden. Tatsächlich wird aber z.B. bei der Wertzuweisung eine Set-Methode aufgerufen, in der die Werte auf Zulässigkeit geprüft werden.
Im folgenden Beispiel wird MaxTagesumsatz durch den Datentyp property zum sogenannten Managed Attribute, der erste Parameter von property gibt eine Referenz auf die Getter-Methode, der zweite Parameter auf die Setter-Methode.

class Konto(object):
 
    # hier kommt der Konstruktor hin
 
    # Getter für den Kontostand
    def kontostand(self):
        return self.__Kontostand
 
    # Getter für das Umsatzlimit
    def maxTagesumsatz(self):
        return self.__MaxTagesumsatz
 
    # Setter für das Umsatzlimit   
    def setMaxTagesumsatz(self, neues_limit):
        if neues_limit > 0:
            self.__MaxTagesumsatz = neues_limit
            return True
        else:
            return False
 
    MaxTagesumsatz = property(maxTagesumsatz, setMaxTagesumsatz)
    # hier kommen die restlichen Methoden hin

Statische Member

Statische Member, also statische Attribute oder statische Methoden, werden verwendet, um Daten und Funktionen zu erstellen, auf die auch ohne das Erzeugen einer Instanz der Klasse zugegriffen werden kann. Ein statisches Attribut existiert in der Klasse genau einmal, alle Objekte der Klasse teilen sich das Attribut.
In Python werden statische Attribute außerhalb des Konstruktors direkt im class-Block definiert. Im folgenden Beispiel wird das statische Attribut Anzahl definiert, das die Zahl der erzeugten Konten speichert. Dazu wird es mit dem Wert 0 initialisiert und bei jedem Aufruf des Konstruktors um 1 erhöht. Beim Aufruf des Destruktors wird der Wert um 1 reduziert. Statt self muss eine Referenz auf die Klasse, hier also Konto vorangestellt werden.

class Konto(object):
    Anzahl = 0
 
    def __init__(self, inhaber, kontonummer, kontostand, max_tagesumsatz=1500):
        self.__Inhaber = inhaber
        self.__Kontonummer = kontonummer
        self.__Kontostand = kontostand
        self.__MaxTagesumsatz = max_tagesumsatz
        self.__UmsatzHeute = 0
        Konto.Anzahl += 1
 
    def __del__(self):
        Konto.Anzahl -= 1
 
    # hier kommen die restlichen Methoden hin

Überladen

Das Überladen von Methoden ist in Python nicht vorgesehen.

Vererbung

Eine Subklasse erbt die Attribute und Methoden einer Basisklasse, indem die Basisklasse bei der Definition in Klammern angegeben wird. Bei dem Beispiel der Klasse Konto werden durch die Angabe class Konto(object) die grundlegenden Eigenschaften eines Objektes vererbt. Soll z.B. eine neue Klasse „Bausparvertrag“ die Attribute und Methoden der Klasse „Konto“ übernehmen, lautet die Definition

class Bausparvertrag(Konto):
 
    ...
    ... 

Überschreiben

Wird eine Methode geerbt aber in anderer Weise benötigt, so kann sie überschrieben werden. Überschreiben heißt im Prinzip neu schreiben oder ersetzen. Die Bezeichnung überschreiben ist nur insofern gehaltvoller, als dass wichtig ist, dass der Name der Methode erhalten bleibt.
Ist eine Methode in der Subklasse überschrieben worden, so lässt sich die gleichnamige Methode der Basisklasse aufrufen, indem statt self der Klassenname vorangestellt wird.

Mehrfachvererbung

In Python ist es möglich, dass eine Subklasse die Attribute und Methoden von mehreren Basisklassen erbt. Existieren beispielsweise die Klassen „Haus“ und „Boot“, so könnte eine Klasse „Hausboot“ definiert werden, die alle Attribute und Methoden eines Hauses und alle Attribute und Methoden eines Bootes erbt. (In Java gibt es die Möglichkeit der Mehrfachvererbung nicht, da die Mehrfachvererbung eine häufige Fehlerquelle darstellt.)

Polymorphie

Polymorphie bedeutet, dass eine Methode mit gleichem Namen in verschiedenen Klassen existiert. Welche Methode für ein gegebenes Objekt benutzt wird, wird erst zur Laufzeit festgelegt, denn dies ist abhängig davon, welcher Klasse das Objekt dann angehört.

Beispiel

Erläuterung

Als Beispiel dient wieder die einfache Bank-Software, die um einige Funktionen erweitert wird, um möglichst viele der oben angesprochenen Punkte umzusetzen. Das Programm selber macht noch nichts, sondern legt nur die Klassen mit ihren Attributen und Methoden fest. Die Erzeugung von Objekten und das Aufrufen der Methoden geschieht von der Kommandozeile aus. Folgende Punkte sollen implementiert werden:

  • Die oben schon benutzte Klasse „Konto“ soll eine Subklasse von „Zaehler“ sein. Die Klasse „Zaehler“ zählt die vorhandenen Instanzen, kann also angeben, wie viele Konten existieren. Dies geschieht mit einem statischen Attribut.
  • Die Klasse „Konto“ bekommt einen versteckten Getter und Setter für den maximalen Tagesumsatz.
  • Es wird eine weitere Klasse „Angestellte“ als Erbe von „Zaehler“ definiert. Damit können nun nicht nur die Konten, sondern nun auch die Angestellten der Bank verwaltet und gezählt werden.
  • Die zwei weiteren Klassen „Sekretaerin“ und „Bankdirektor“ erben die Attribute und Methoden von „Angestellte“ und erweitern diese.

Python-Code

class Zaehler(object):
    Anzahl = 0
 
    def __init__(self):
        type(self).Anzahl += 1
 
    def __del__(self):
        type(self).Anzahl -= 1
 
 
class Konto(Zaehler):
 
    # Konstruktor für Konto
    def __init__(self, inhaber, kontonummer, kontostand, max_tagesumsatz=1500):
        Zaehler.__init__(self)
        self.__Inhaber = inhaber
        self.__Kontonummer = kontonummer
        self.__Kontostand = kontostand
        self.__MaxTagesumsatz = max_tagesumsatz
        self.__UmsatzHeute = 0
        print "Es wurde ein neues Konto eröffnet!"
 
    # Destruktor für Konto
    def __del__(self):
        Zaehler.__del__(self)
        print "Das Konto wurde aufgelöst!"
 
    # Betrag auf Konto einzahlen
    def einzahlen(self, betrag):
        if self.__UmsatzHeute + betrag <= self.__MaxTagesumsatz:
            self.__Kontostand += betrag
            self.__UmsatzHeute += betrag
            print "Der gewünschte Betrag wurde eingezahlt."
        else:
            print "Eine Einzahlung ist leider nicht möglich!"
 
    # Kontodaten anzeigen
    def anzeigen(self):
        print "Kontoinhaber:         ",self.__Inhaber
        print "Kontonummer:          ",self.__Kontonummer
        print "Kontostand:            %.2f Euro"%(self.__Kontostand)
        print "Maximaler Tagesumsatz: %.2f Euro"%(self.__MaxTagesumsatz)
        print "Heutiger Umsatz:       %.2f Euro"%(self.__UmsatzHeute)
 
    # Getter für das Umsatzlimit
    def maxTagesumsatz(self):
        return self.__MaxTagesumsatz
 
    # Setter für das Umsatzlimit   
    def setMaxTagesumsatz(self, neues_limit):
        if type(neues_limit) in (float, int) and neues_limit > 0:
            self.__MaxTagesumsatz = neues_limit
            print "Das Limit wurde geändert!"
        else:
            print "Unzulässiger Wert! Das Limit wurde nicht geändert."
 
    # Managed Attribute mit verstecktem Getter und Setter
    MaxTagesumsatz = property(maxTagesumsatz, setMaxTagesumsatz)
 
 
class Angestellter(Zaehler):
 
    # Konstruktor für Angestellte
    def __init__(self, name, stundenlohn, stunden_pro_woche):
        Zaehler.__init__(self)
        self.Name = name
        self.Stundenlohn = stundenlohn
        self.StundenProWoche = stunden_pro_woche
 
    # Personaldaten anzeigen
    def anzeigen(self):
        print "Name:         ",self.Name
        print "Stundenlohn:  ",self.Stundenlohn
        print "Wochenstunden:",self.StundenProWoche 
 
 
class Sekretaerin(Angestellter):
 
    # Konstruktor für Sekretärin
    def __init__(self, name):
        Angestellter.__init__(self, name, 15, 30)
 
 
class Bankdirektor(Angestellter):
 
    # Konstruktor für Bankdirektor
    def __init__(self, name, dienstwagen):
        Angestellter.__init__(self, name, 150, 50)
        self.Dienstwagen = dienstwagen
 
    # Personaldaten anzeigen (Methode überschreiben)
    def anzeigen(self):
        Angestellter.anzeigen(self)
        print "Dienstwagen:  ",self.Dienstwagen

Ausprobieren im interaktiven Modus

Konten einrichten und auflösen, zählen der vorhandenen Konten:

>>> Konto.Anzahl
0
>>> k1=Konto("Max",1234,100)
Es wurde ein neues Konto eröffnet!
>>> k2=Konto("Moritz",5678,249.90,1000)
Es wurde ein neues Konto eröffnet!
>>> Konto.Anzahl
2
>>> k1.Anzahl
2
>>> del k1
Das Konto wurde aufgelöst!
>>> k1.Anzahl

Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    k1.Anzahl
NameError: name 'k1' is not defined
>>> Konto.Anzahl
1
>>> del k2
Das Konto wurde aufgelöst!
>>> Konto.Anzahl
0

Anzeigen und einzahlen unter Berücksichtigung des Tagesumsatzes:

>>> k1=Konto("Bibbi Blocksberg",1080965,2745.2,1000)
Es wurde ein neues Konto eröffnet!
>>> k1.anzeigen
<bound method Konto.anzeigen of <__main__.Konto object at 0x11c9e70>>
>>> k1.anzeigen()
Kontoinhaber:          Bibbi Blocksberg
Kontonummer:           1080965
Kontostand:            2745.20 Euro
Maximaler Tagesumsatz: 1000.00 Euro
Heutiger Umsatz:       0.00 Euro
>>> k1.einzahlen(800)
Der gewünschte Betrag wurde eingezahlt.
>>> k1.anzeigen()
Kontoinhaber:          Bibbi Blocksberg
Kontonummer:           1080965
Kontostand:            3545.20 Euro
Maximaler Tagesumsatz: 1000.00 Euro
Heutiger Umsatz:       800.00 Euro
>>> k1.einzahlen(300)
Eine Einzahlung ist leider nicht möglich!
>>> k1.anzeigen()
Kontoinhaber:          Bibbi Blocksberg
Kontonummer:           1080965
Kontostand:            3545.20 Euro
Maximaler Tagesumsatz: 1000.00 Euro
Heutiger Umsatz:       800.00 Euro

Benutzung des verwalteten Attributes „MaxTagesumsatz“, das die versteckte Get- und Set-Methode aufruft:

>>> k1=Konto("Donald Duck",246810,120.55,200)
Es wurde ein neues Konto eröffnet!
>>> k1.MaxTagesumsatz
200
>>> k1.MaxTagesumsatz = 400
Das Limit wurde geändert!
>>> k1.MaxTagesumsatz = -2
Unzulässiger Wert! Das Limit wurde nicht geändert.
>>> k1.MaxTagesumsatz = "Unsinn"
Unzulässiger Wert! Das Limit wurde nicht geändert.
>>> k1.anzeigen()
Kontoinhaber:          Donald Duck
Kontonummer:           246810
Kontostand:            120.55 Euro
Maximaler Tagesumsatz: 400.00 Euro
Heutiger Umsatz:       0.00 Euro

Definieren einiger Objekte des Typs „Angestellter“, ausführen der geerbten und überschriebenen Methode „anzeigen“

>>> a=Angestellter("Hans Wurst",20,40)
>>> s=Sekretaerin("Bibbi Bleistift")
>>> b=Bankdirektor("Siggi Superreich","Cadillac")
>>> a.anzeigen()
Name:          Hans Wurst
Stundenlohn:   20
Wochenstunden: 40
>>> s.anzeigen()
Name:          Bibbi Bleistift
Stundenlohn:   15
Wochenstunden: 30
>>> b.anzeigen()
Name:          Siggi Superreich
Stundenlohn:   150
Wochenstunden: 50
Dienstwagen:   Cadillac

Zählen der Objekte. Beachte: Eine Sekretärin wird nicht als „Angestellter“ gezählt, ebenso wenig wie der Bankdirektor.

>>> k1=Konto("Max",123,100)
Es wurde ein neues Konto eröffnet!
>>> k2=Konto("Moritz",456,100)
Es wurde ein neues Konto eröffnet!
>>> a=Angestellter("Hans",20,40)
>>> b=Bankdirektor("Siggi","Fiat")
>>> s1=Sekretaerin("Bibbi")
>>> s2=Sekretaerin("Lilli")
>>> Konto.Anzahl;Angestellter.Anzahl;Sekretaerin.Anzahl;Bankdirektor.Anzahl
2
1
2
1
>>> del a
>>> Konto.Anzahl;Angestellter.Anzahl;Sekretaerin.Anzahl;Bankdirektor.Anzahl
2
0
2
1
>>> del s2
>>> Konto.Anzahl;Angestellter.Anzahl;Sekretaerin.Anzahl;Bankdirektor.Anzahl
2
0
1
1
Cookies helfen bei der Bereitstellung von Inhalten. Durch die Nutzung dieser Seiten erklären Sie sich damit einverstanden, dass Cookies auf Ihrem Rechner gespeichert werden. Weitere Information
Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht: CC Attribution-Noncommercial-Share Alike 4.0 International