Python Objektorientierte Programmierung: Umfassender Leitfaden
Überblick über OOP-Terminologie
- Klasse – Benutzerdefinierter Prototyp für ein Objekt, der eine Menge von Attributen definiert, die jedes Objekt der Klasse charakterisieren. Attribute sind Datenelemente (Klassenvariablen und Instanzvariablen) und Methoden, über Punktnotation zugreifbar.
- Klassenvariable – Variable, die von allen Instanzen einer Klasse geteilt wird. Definiert innerhalb der Klasse, aber außerhalb aller Methoden. Weniger häufig als Instanzvariablen.
- Datenelement – Klassenvariable oder Instanzvariable, die Daten hält, die mit einer Klasse und ihren Objekten assoziiert sind.
- Funktionsüberladung – Zuweisung mehrerer Verhaltensweisen zu einer Funktion. Die ausgeführte Operation variiert nach Typ der beteiligten Objekte oder Argumente.
- Instanzvariable – Variable, die innerhalb einer Methode definiert ist und nur der aktuellen Instanz einer Klasse gehört.
- Vererbung – Übertragung der Merkmale einer Klasse auf andere, davon abgeleitete Klassen.
- Instanz – Ein einzelnes Objekt einer bestimmten Klasse. Ein Objekt
objder KlasseCircleist eine Instanz vonCircle. - Instanziierung – Erstellung einer Instanz einer Klasse.
- Methode – Spezielle Funktion, die in einer Klassendefinition definiert ist.
- Objekt – Eindeutige Instanz einer durch ihre Klasse definierten Datenstruktur. Enthält sowohl Datenelemente (Klassen- und Instanzvariablen) als auch Methoden.
- Operatorüberladung – Zuweisung mehrerer Funktionen zu einem Operator.
Klassen erstellen
Die class-Anweisung erstellt eine neue Klassendefinition. Der Klassenname folgt unmittelbar auf das Schlüsselwort class und einen Doppelpunkt:
class ClassName:
'Optional class documentation string'
class_suite
- Die Klasse hat einen Dokumentationsstring, zugänglich über
ClassName.__doc__. class_suitebesteht aus allen Anweisungen, die Klassenmember, Datattribute und Funktionen definieren.
Beispiel
class Employee:
'Common base class for all employees'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print("Total Employee %d" % Employee.empCount)
def displayEmployee(self):
print("Name :", self.name, ", Salary:", self.salary)
empCountist eine Klassenvariable, deren Wert unter allen Instanzen geteilt wird. Zugriff überEmployee.empCount.__init__()ist eine spezielle Methode (Konstruktor/Initialisierer), die Python aufruft, wenn eine neue Instanz erstellt wird.- Andere Klassenmethoden werden wie normale Funktionen deklariert, wobei das erste Argument
selfist. Python fügtselfautomatisch hinzu; Sie müssen es beim Aufruf nicht angeben.
Instanzobjekte erstellen
Um Instanzen einer Klasse zu erstellen, rufen Sie die Klasse mit ihrem Namen auf und übergeben die Argumente, die __init__ akzeptiert:
emp1 = Employee("Zara", 2000)
emp2 = Employee("Manni", 5000)
Attribute zugreifen
Objektattribute werden über den Punktoperator mit dem Objekt zugegriffen. Klassenvariablen über den Klassennamen:
emp1.displayEmployee()
emp2.displayEmployee()
print("Total Employee %d" % Employee.empCount)
Komplettes Beispiel
#!/usr/bin/python
class Employee:
'Common base class for all employees'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print("Total Employee %d" % Employee.empCount)
def displayEmployee(self):
print("Name :", self.name, ", Salary:", self.salary)
emp1 = Employee("Zara", 2000)
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print("Total Employee %d" % Employee.empCount)
Ausgabe:
Name : Zara , Salary: 2000 Name : Manni , Salary: 5000 Total Employee 2
Attribute können jederzeit hinzugefügt, entfernt oder geändert werden:
emp1.age = 7 # 'age' hinzufügen emp1.age = 8 # 'age' ändern del emp1.age # 'age' löschen
Alternativ können Sie folgende Funktionen verwenden:
getattr(obj, name[, default])– Attribut eines Objekts abrufen.hasattr(obj, name)– Prüfen, ob Attribut existiert.setattr(obj, name, value)– Attribut setzen. Erstellt es, falls nicht existent.delattr(obj, name)– Attribut löschen.
hasattr(emp1, 'age') # True, falls 'age' existiert getattr(emp1, 'age') # Wert von 'age' setattr(emp1, 'age', 8) # 'age' auf 8 setzen delattr(emp1, 'age') # 'age' löschen
Eingebaute Klassenattribute
Jede Python-Klasse besitzt folgende eingebaute Attribute, zugänglich über den Punktoperator:
- __dict__ – Dictionary mit dem Namensraum der Klasse.
- __doc__ – Dokumentationsstring der Klasse oder
None, falls undefiniert. - __name__ – Klassenname.
- __module__ – Modulname, in dem die Klasse definiert ist.
"__main__"im interaktiven Modus. - __bases__ – Tupel mit den Basisklassen in Reihenfolge ihres Auftretens.
Beispiel
#!/usr/bin/python
class Employee:
'Common base class for all employees'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print("Total Employee %d" % Employee.empCount)
def displayEmployee(self):
print("Name :", self.name, ", Salary:", self.salary)
print("Employee.__doc__:", Employee.__doc__)
print("Employee.__name__:", Employee.__name__)
print("Employee.__module__:", Employee.__module__)
print("Employee.__bases__:", Employee.__bases__)
print("Employee.__dict__:", Employee.__dict__)
Ausgabe:
Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount': , 'empCount': 2, 'displayEmployee': , '__doc__': 'Common base class for all employees', '__init__': }
Objekte zerstören (Garbage Collection)
Python löscht nicht mehr benötigte Objekte (eingebaute Typen oder Klasseninstanzen) automatisch, um Speicher freizugeben. Der Prozess, bei dem Python periodisch Speicherblöcke zurückfordert, die nicht mehr verwendet werden, heißt Garbage Collection.
Pythons Garbage Collector läuft während der Programmausführung und wird ausgelöst, wenn der Referenzzähler eines Objekts null erreicht. Der Referenzzähler ändert sich mit der Anzahl der Aliase, die auf das Objekt verweisen.
- Erhöht sich bei Zuweisung eines neuen Namens oder Platzierung in einem Container (Liste, Tupel, Dictionary).
- Verringert sich bei
del, Neuzuweisung der Referenz oder Verlassen des Gültigkeitsbereichs. - Bei Erreichen von null wird das Objekt automatisch eingesammelt.
a = 40 # Objekt <40> erstellen b = a # Ref.-Count von <40> erhöhen c = [b] # Ref.-Count von <40> erhöhen del a # Ref.-Count von <40> verringern b = 100 # Ref.-Count von <40> verringern c[0] = -1 # Ref.-Count von <40> verringern
Normalerweise bemerken Sie nicht, wann der Garbage Collector ein verwaistes Objekt zerstört. Eine Klasse kann jedoch die spezielle Methode __del__() (Destruktor) implementieren, die aufgerufen wird, wenn die Instanz kurz vor der Zerstörung steht. Diese Methode kann zum Aufräumen nicht-speicherbezogener Ressourcen dienen.
Beispiel
#!/usr/bin/python
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __del__(self):
class_name = self.__class__.__name__
print(class_name, "destroyed")
pt1 = Point()
pt2 = pt1
pt3 = pt1
print(id(pt1), id(pt2), id(pt3))
del pt1
del pt2
del pt3
Ausgabe:
3083401324 3083401324 3083401324 Point destroyed
Hinweis: Idealerweise definieren Sie Ihre Klassen in separaten Dateien und importieren sie in Ihr Hauptprogramm mit import.
Klassenvererbung
Statt von Grund auf neu zu beginnen, können Sie eine Klasse ableiten, indem Sie die Elternklasse in Klammern nach dem neuen Klassennamen auflisten.
Die Kindklasse erbt die Attribute der Elternklasse und kann diese nutzen, als wären sie in der Kindklasse definiert. Eine Kindklasse kann auch Datenelemente und Methoden der Elternklasse überschreiben.
Syntax
class SubClassName(ParentClass1[, ParentClass2, ...]):
'Optional class documentation string'
class_suite
Beispiel
#!/usr/bin/python
class Parent:
parentAttr = 100
def __init__(self):
print("Calling parent constructor")
def parentMethod(self):
print('Calling parent method')
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print("Parent attribute :", Parent.parentAttr)
class Child(Parent):
def __init__(self):
print("Calling child constructor")
def childMethod(self):
print('Calling child method')
c = Child()
c.childMethod()
c.parentMethod()
c.setAttr(200)
c.getAttr()
Ausgabe:
Calling child constructor Calling child method Calling parent method Parent attribute : 200
Mehrfachvererbung:
class A: ... class B: ... class C(A, B): ...
Beziehungen prüfen:
issubclass(sub, sup)– GibtTruezurück, wennsubUnterklasse vonsupist.isinstance(obj, Class)– GibtTruezurück, wennobjInstanz vonClassoder einer Unterklasse ist.
Methoden überschreiben
Sie können Methoden der Elternklasse immer überschreiben. Ein Grund: Sie möchten in Ihrer Unterklasse spezielle oder andere Funktionalität.
Beispiel
#!/usr/bin/python
class Parent:
def myMethod(self):
print('Calling parent method')
class Child(Parent):
def myMethod(self):
print('Calling child method')
c = Child()
c.myMethod()
Ausgabe:
Calling child method
Basismethoden überladen
Folgende generische Funktionalitäten können Sie in eigenen Klassen überschreiben:
| Nr. | Methode, Beschreibung & Beispielaufruf |
|---|---|
| 1 | __init__(self[, args...]) – Konstruktor. Aufruf: obj = ClassName(args) |
| 2 | __del__(self) – Destruktor. Aufruf: del obj |
| 3 | __repr__(self) – Auswertbare String-Repräsentation. Aufruf: repr(obj) |
| 4 | __str__(self) – Druckbare String-Repräsentation. Aufruf: str(obj) |
| 5 | __cmp__(self, x) – Objektvergleich. Aufruf: cmp(obj, x) |
Operatoren überladen
Angenommen, Sie haben eine Vector-Klasse für zweidimensionale Vektoren. Was passiert bei +? Python würde einen Fehler werfen.
Definieren Sie __add__ in Ihrer Klasse für Vektoraddition, dann verhält sich + wie erwartet:
#!/usr/bin/python
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self, other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2, 10)
v2 = Vector(5, -2)
print(v1 + v2)
Ausgabe:
Vector (7, 8)
Datenversteckung
Objektattribute können außerhalb der Klassendefinition sichtbar sein oder nicht. Benennen Sie Attribute mit doppeltem Unterstrich-Präfix (__), dann sind sie für Außenstehende nicht direkt sichtbar.
Beispiel
#!/usr/bin/python
class JustCounter:
__secretCount = 0
def count(self):
self.__secretCount += 1
print(self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print(counter.__secretCount)
Ausgabe:
1 2 Traceback (most recent call last): File "test.py", line 12, inprint(counter.__secretCount) AttributeError: JustCounter instance has no attribute '__secretCount'
Python schützt diese Member, indem es den Namen intern um den Klassennamen erweitert. Zugriff ist über object._className__attrName möglich. Ersetzen Sie die letzte Zeile:
print(counter._JustCounter__secretCount)
Ausgabe:
1 2 2
Python
- C# Klassen & Objekte: Fundamente für robustes OOP
- Python-Datentypen meistern: Praxisleitfaden
- Python-Operatoren meistern: Umfassender Leitfaden
- Python pass-Statement meistern: Praxisleitfaden
- Python-Dictionaries meistern: Erstellung, Manipulation und fortgeschrittene Techniken
- Python benutzerdefinierte Exceptions: Ein praktischer Leitfaden
- Python Objektorientierte Programmierung meistern: Klassen, Vererbung, Kapselung & Polymorphie
- Python Vererbung meistern: Konzepte, Syntax und praktische Beispiele
- Java Singleton-Pattern erklärt: Sichere Implementierung und Verwendung
- Automatisiertes vision-basiertes Objekttracking mit Raspberry Pi und OpenCV