Früher oder später sieht sich ein fortgeschrittener Einsteiger auf seinem Weg zum Programmierer
mit der objektorientierten Programmierung konfrontiert und bei dem einem oder anderen sehen anfänglich alle Beispiele
verwirrend aus. Doch das braucht nicht zu sein und deshalb haben wir einige einfache Beispiele für den leichteren
Einstieg in die objektorientierte Programmierung mit Python 3 zusammengestellt.
Auf das Für und Wider einer objektorientierten Programmierung möchten wir an dieser Stelle nicht eingehen, es
geht bis zu einem gewissen Grade auch ohne OOP. Doch wer mit der objektorientierten Programmierung beginnt, sollte
sich weitestgehend an die allgemeinen Spielregeln (Konvention) halten und zu diesen gehört, dass es sich beim
Bezeichner einer Klasse um ein Substantiv handeln sollte. Über ein zusammengesetztes Substantiv in der
CamelCase-Schreibweise, die bei Python mit CapWords bezeichnet wird, dürfte sich niemand beschweren.
Ob hinter dem Bezeichner der Klasse eine Notation wie die folgende mit (object) folgt, ist hingegen bei
neueren Versionen von Python optional, so lange es sich um keine erbende Klasse handelt. Ebenfalls ist ein Doc-String
optional, der, insofern einer verwendet wird, eine Kurzbeschreibung der Klasse enthalten sollte.
class Bezeichner(object): """Doc-String mit Kurzbeschreibung der Klasse"""
Bei den Bezeichnern von selbstdefinierten Funktionen sind zwei Schreibweisen weit verbreitet, wobei von den Entwicklern von Python die zweite favorisiert wird.
def camelCase():
def camel_case():
Wenn wir anfänglich auf unseren Seiten die erste Variante bevorzugten, so aus dem Grunde,
weil die erste Schreibweise im deutschsprachigen Raum mehr an die natürliche Sprache und Schreibweise angelehnt
ist und somit leichter lesbar. Im englischen Sprachraum mag es sich umgekehrt verhalten. Funktional sind sich
beide Schreibweisen gleichgestellt. Bei nachträglichen Überarbeitungen halten wir uns zwischenzeitlich zunehmend
an die zweite Variante.
Weiterhin sei erwähnt, für die Verknüpfung von Variablen mit Strings gibt es unterschiedliche Varianten, wobei
die erste Variante mit dem + Operator zwar eine praktische Alternative zur formatierten Ausgabe darstellt, doch
die .format() Methode letztendlich mehr zu bieten hat, z.B. wenn es um die Formatierung von Zahlen geht. Es schadet
zumindest nichts, sich von Anbeginn an mit dieser Methode anzufreunden.
Ausgabe:
Ein String mit einer Variablen.
Ein String mit einer Variablen.
Ein String mit einer Summe von 63.00.
Ein String mit einer Summe von 063.
Doch kommen wir zur ersten Klasse, diese enthält nur einige Klassen-Variablen. Allgemein werden Variablen innerhalb einer Klasse je nach Sprache auch noch als Attribute, Member oder Eigenschaften bezeichnet. Unterhalb der Klasse sind unterschiedliche Varianten aufgeführt, um auf diese Klassen-Variablen oder Eigenschaften zuzugreifen und zu verwenden. Die Bezeichnung Attribute ist nicht nur in Python gebräuchlich und nebebei bemerkt, eigentlich wird jeder Wert mit einem Parameter an eine Funktion oder Methode übergeben und innerhalb einer Funktion oder Methode als Argument benutzt.
Erste Klasse:
# Erstellung und Definition der Klasse Mensch class Mensch: """Der evolutionäre Stammbaum des Menschen als Klasse""" ordnung = "Primaten" teilordg = "Altweltaffen" ueberfam = "Menschenartige" familie = "Menschenaffen" tribus = "Hominini" gattung = "Homo" spezies = "Mensch" # Instanziieren von Objekten der Klasse Mensch # Variante 1: print(Mensch.ordnung) # Variante 2: print(Mensch().tribus) # Variante 3: stammbaum = Mensch() print("Der {0} gehört zur Familie der {1}.\n".format( stammbaum.spezies, stammbaum.familie))
Ausgabe:
Primaten
Hominini
Der Mensch gehört zur Familie der Menschenaffen.
Bei der ersten Klasse handelt es sich bereits um eine richtige Klasse, von der Instanzen
als Vertreter dieser Klasse erzeugt wurden. Dennoch würde deren Einsatz noch nicht allzu viel Sinn ergeben, um gleich
alles auf OOP umzustellen und nur noch objektorientiert zu programmieren, da noch keine Methoden enthalten sind,
die etwas bewirken könnten. Auch sollten Klassen erst dann benutzt werden, wenn einfache Funktionen nicht mehr
genügen. Eher ist es üblich, aus Klassen ebenfalls auf Funktionen als Gehilfen zurückzugreifen.
Bei Methoden handelt es sich lediglich um einen anderen Namen für Funktionen, da jede selbstdefinierte Funktion
innerhalb einer Klasse als Methode bezeichnet wird.
Zweite Klasse:
# Erstellung und Definition der Klasse Systematik class Systematik: """ Klasse der Systematik des evolutionären Stammbaums des Menschen """ klasse = "Säugetiere" ordnung = "Primaten" teilordg = "Altweltaffen" ueberfam = "Menschenartigen" familie = "Menschenaffen" tribus = "Hominini" gattung = "Homo" spezies = "Mensch" def ordne_spezies(): ausgabe = "Die Spezies Mensch gehört zur Überfamilie der " ausgabe += Systematik.ueberfam + "." print(ausgabe) def ordne_familie(): return "Die Überfamilie der {0} gehört " \ "zur Klasse der {1}.\n".format( Systematik.ueberfam, Systematik.klasse) # Instanziieren von Objekten der Klasse Systematik # Variante 1: Systematik.ordne_spezies() # Variante 2: stammbaum = Systematik print(stammbaum.ordne_familie())
Ausgabe:
Die Spezies Mensch gehört zur Überfamilie der Menschenartigen.
Die Überfamilie der Menschenartigen gehört zur Klasse der Säugetiere.
Die zweite Klasse enthält bereits zwei Methoden, die jeweils eine Funktion erfüllen. Was jedoch noch fehlt, ist eine einfache Möglichkeit, mit der sich diese Funktionen nach eigenen Vorstellungen oder entsprechend eines Programmablaufs wenigstens etwas steuern lassen.
Dritte Klasse:
# Erstellung und Definition der Klasse Eigenschaften class Eigenschaften: """Klasse mit menschlichen Eigenschaften""" # Klassen-Variablen/Eigenschaften eigenheit = "spendabel" charakter = "aufrichtig" def setze_eigenschaft(wert): Eigenschaften.eigenheit = wert def liefere_eigenschaft(): return "Einige Menschen sind {}".format(Eigenschaften.eigenheit) # Instanziieren von Objekten der Klasse Eigenschaften # Erster Instanz erste_instanz = Eigenschaften erste_instanz.setze_eigenschaft("gierig") print(erste_instanz.liefere_eigenschaft()) # Zweite Instanz zweite_instanz = Eigenschaften print(zweite_instanz.liefere_eigenschaft())
Ausgabe:
Erster Instanz:
Einige Menschen sind gierig
Zweite Instanz:
Einige Menschen sind gierig
Die dritte Klasse enthält bereits eine Methode, die ein Programmierer als kleine Schnittelle
benutzen könnte, um die vorgegebenen menschlichen Eigenschaften innerhalb der Klasse durch neue Werte zu verändern
und dadurch die Antwort der zweiten Methode zu beeinflussen. Doch einmal gesetzte oder veränderte Eigenschaften
von Klassen-Variablen bleiben für alle nachfolgenden Instanzen für die Laufzeit einer Anwendung gleich, bis diesen
Eigenschaften ein neuer Wert zugewiesen wird.
Klassen-Variablen werden aus diesem Grund auch als statische Eigenschaften bezeichnet. Je nach Einsatz können
statische Eigenschaften erwünscht sein, doch oftmals sind sie es nicht.
Vierte Klasse:
# Erstellung und Definition der Klasse Charaktere class Charaktere: """Klasse mit menschlichen Charaktereigenschaften""" def __init__(self, eigenheit="spendabel", charakter="aufrichtig"): # Instanz-Variablen / Attribute - Eigenschaften self.eigenheit = eigenheit self.charakter = charakter def liefere_eigenschaft(self): return "Einige Menschen sind {0}".format(self.eigenheit) # Instanziieren von Objekten der Klasse Charaktere # Erster Instanz erste_instanz = Charaktere("gierig") print(erste_instanz.liefere_eigenschaft()) # Zweite Instanz zweite_instanz = Charaktere() print(zweite_instanz.liefere_eigenschaft())
Ausgabe:
Erster Instanz:
Einige Menschen sind gierig
Zweite Instanz:
Einige Menschen sind spendabel
Um nicht nur mit statischen Eigenschaften zu arbeiten, werden in der vierten Klasse die
gewünschten Eigenschaften nicht als Klassen-Variablen, sondern als Instanz-Variablen mit Hilfe der Initialisierungsmethode
__init__ angelegt. Die Initialisierungsmethode wird oftmals mit einer Konstruktor-Methode gleichgesetzt, dennoch
ist es nur eine Initialisierungsmethode, die jedoch, falls vorhanden, automatisch mit aufgerufen wird, wenn ein
neues Objekt einer Klasse wie im Beispiel mit
variable = KlassenBezeicher()
instanziiert wird. Wer nun die Ausgaben von den Instanzen der dritten der vierten Klasse vergleicht, wird den
Unterschied erkennen. Die in erster Instanz veränderte Eigenschaft hatte bei der vierten Klasse keine Auswirkungen
auf das Ergebnis der zweiten Instanz, nur die Schreibweise ist gewöhnungsbedürftig. Dazu sollte ein Programmierer
wissen, der Parameter "self" entspricht einer Referenz auf das instanziierte Objekt, wodurch die Methode und alle
Eigenschaften, die mit "self" verknüpft werden, ebenfalls mit der Instanz verknüpft werden.
Falls der eine oder andere Leser an dieser Stelle mit einem Verständnisproblem zu kämpfen hat, ein kleiner Tipp.
In der Regel werden im Quelltext einer Webseite auch keine Images eingebunden, sondern nur deren Adressen als Referenz
auf eine Quelle. Ein Browser erkennt diese Referenz, ladet die referenzierten Imagedateien und verbindet die Images
mit der Webseite.
Noch etwas gewöhnungsbedürftiger wird es, wenn Eigenschaften als Klassen-Variablen und als Instanz-Variablen
in einer Klasse vereint werden, um beide in den Programmlauf mit einzubeziehen, wie im nächsten Beispiel.
Es sei angemerkt, in beiden Beispielen wurden mehr Parameter mit einem Default-
# Erstellung und Definition der Klasse Tribus class Tribus: """Klasse mit einer Zuordnung zum Tribus""" # Klassen-Variablen / Attribute - Eigenschaften vorname = "Name" nachname = "Nachname" standard = "Standard" def __init__(self, zugehoerigleit="default", einordnung="tierisch"): # Instanz-Variablen / Attribute - Eigenschaften self.zugehoerigleit = zugehoerigleit self.einordnung = einordnung def setze_klassenattribute(self, value01, value02): Tribus.vorname = value01 Tribus.nachname = value02 def liefere_klassenattribute(self): if self.vorname is "John": return "{0} {1} entspricht dem männlichen {2}.".format( self.vorname, self.nachname, self.standard) elif self.vorname is "Jane": return "{0} {1} entspricht dem weiblichen {2}.".format( self.vorname, self.nachname, self.standard) else: return "Nicht eingeplant!\n" def liefere_instanzattribute(self): return "Beide sind von {0:s}er Natur.\n".format( self.zugehoerigleit) # Nur für eine Kontrolle der Eigenschaften und Werte. def kontrolliere_eigenschaften(self): return "Klassen-Variable: {0:s}\n" \ "Klassen-Variable: {1:s}\n" \ "Instanz-Variable: {2:s}\n" \ "Instanz-Variable: {3:s}\n".format( self.vorname, self.nachname, self.standard, self.zugehoerigleit) # Instanziieren von Objekten der Klasse Eigenschaften # Erster Instanz erste_instanz = Tribus("menschlich") erste_instanz.setze_klassenattribute("John", "Doe") print(erste_instanz.liefere_klassenattribute()) erste_instanz.setze_klassenattribute("Jane", "Doe") print(erste_instanz.liefere_klassenattribute()) print(erste_instanz.liefere_instanzattribute()) # Zweite Instanz zweite_instanz = Tribus() print(zweite_instanz.kontrolliere_eigenschaften())
Ausgabe:
Erster Instanz:
John Doe entspricht dem männlichen Standard.
Jane Doe entspricht dem weiblichen Standard.
Beide sind von menschlicher Natur.
Zweite Instanz:
Klassen-Variable: Jane
Klassen-Variable: Doe
Klassen-Variable: Standard
Instanz-Variable: default
In der ersten Instanz werden mit Hilfe der Methode "setze_klassenattribute" den
Klassen-Eigenschaften neue Werte zugewiesen. Wichtig ist dabei, dass die Klassen-Variablen mit der Klasse verknüpft
bleiben und nicht über self mit den instanziierten Objekten verknüpft werden.
Muster:
KlassenBezeicher.eigenschaft = neuer Wert
Erst im weiteren Verlauf können diese dann im Zusammenspiel mit self benutzt werden, insofern keine anderen Gründe dagegen sprechen. Im Beispiel waren wie erwartet, die den Klassen-Variablen in erster Instanz zugewiesenen Werte auch in zweiter Instanz verfügbar. Die Instanz-Variable nahm hingegen, ebenfalls wie erwartet, wieder ihren Default-Wert an.
Weiterlesen » Vererbung und Sichtbarkeit
Einstieg in Python
OOP mit Python
Codes & Tutorials
Kleines Projekt