Dieser Leitfaden behandelt objektorientierte Programmierung (OOP) in Python und Kontextmanager, einschließlich praktischer Beispiele zur Erfassung von stdout/stderr und Verwendung des Tee-Musters, um Ausgaben gleichzeitig anzuzeigen und zu erfassen.
1. Klassen in Python
Klassen sind ein zentraler Mechanismus der OOP. Eine Klasse ist eine Vorlage, um Objekte mit Attributen (Daten) und Methoden (Funktionen) zu erstellen. Objekte, die aus einer Klasse erstellt werden, heißen Instanzen. Klassen helfen, Code zu strukturieren, die Wiederverwendbarkeit zu erhöhen und die Wartung zu erleichtern.
Aufbau einer Klasse
class ClassName:
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
def method(self):
return f'{self.param1} und {self.param2}'
Wichtige Punkte:
__init__: Konstruktor zum Initialisieren von Objektattributen.self: Referenz auf die aktuelle Instanz.- Attribute: werden über
selfdefiniert und sind in allen Methoden verfügbar. - Methoden: arbeiten mit den Daten des Objekts.
Objekte erstellen
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def description(self):
return f'{self.year} {self.make} {self.model}'
my_car = Car('Toyota', 'Corolla', 2020)
print(my_car.description()) # Ausgabe: 2020 Toyota Corolla
Methodenarten
- Instanzmethoden — arbeiten auf Objekten (
self). - Klassenmethoden — arbeiten auf der Klasse (
cls) über@classmethod. - Statische Methoden — unabhängig von Instanz und Klasse (
@staticmethod).
Vererbung
class Animal:
def speak(self):
return 'Tierlaut'
class Dog(Animal):
def speak(self):
return 'Wuff'
Polymorphismus
class Cat(Animal):
def speak(self):
return 'Miau'
cat = Cat()
print(cat.speak()) # Ausgabe: Miau
- Dieselbe Methode funktioniert je nach Objekttyp unterschiedlich.
Kapselung
class Car:
def __init__(self, make, model):
self._make = make # Geschütztes Attribut
self._model = model
def get_make(self):
return self._make
def set_make(self, make):
self._make = make
Magische Methoden und Destruktor
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'Point({self.x}, {self.y})'
p = Point(3, 4)
print(p) # Ausgabe: Point(3, 4)
ASCII-Diagramm: Vererbung und Polymorphismus
┌─────────┐
│ Animal │
└─────────┘
│ speak() │
└─────────┘
▲
┌───────┴────────┐
│ │
┌─────────┐ ┌─────────┐
│ Dog │ │ Cat │
└─────────┘ └─────────┘
│ speak() │ │ speak() │
└─────────┘ └─────────┘
2. Kontextmanager in Python
Kontextmanager ermöglichen automatisches Zuweisen und Freigeben von Ressourcen, auch bei Fehlern.
Verwendung von @contextmanager
from contextlib import contextmanager
@contextmanager
def my_context():
print("Betritt den Kontext")
try:
yield "Ressource"
finally:
print("Verlässt den Kontext")
Verwendung:
with my_context() as res:
print("Im Kontext:", res)
Erfassen von stdout/stderr und Tee
Python erlaubt das Erfassen von stdout, stderr oder beidem und die gleichzeitige Anzeige und Erfassung mit dem Tee-Muster.
3. Vollständiges Beispiel: oop_and_context.py
"""
oop_and_context.py
Beispiele für Klassen, OOP-Prinzipien und Kontextmanager in Python.
Enthält:
- Definition von Klassen, Vererbung, Polymorphismus, Kapselung
- Instanz-, Klassen- und statische Methoden
- Magische Methoden und Destruktor
- Kontextmanager mit @contextmanager
- Erfassen von stdout, stderr und kombiniert
- Tee-Muster: gleichzeitig anzeigen und erfassen
- Klassenbasierter Kontextmanager
"""
import sys
import io
from contextlib import contextmanager
# ==========================
# Teil 1: Klassen und OOP
# ==========================
class Animal:
"""Basisklasse für Tiere."""
def speak(self):
return 'Tierlaut'
class Dog(Animal):
def speak(self):
return 'Wuff'
class Cat(Animal):
def speak(self):
return 'Miau'
class Car:
"""Beispiel für Kapselung."""
def __init__(self, make, model, year=None):
self._make = make
self._model = model
self.year = year
def get_make(self):
return self._make
def set_make(self, make):
self._make = make
def description(self):
if self.year:
return f'{self.year} {self._make} {self._model}'
return f'{self._make} {self._model}'
class Point:
"""Klasse mit magischen Methoden."""
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'Point({self.x}, {self.y})'
# ==========================
# Teil 2: Kontextmanager
# ==========================
@contextmanager
def my_context():
print("Betritt den Kontext")
try:
yield "Ressource"
finally:
print("Verlässt den Kontext")
@contextmanager
def capture_stdout():
old_stdout = sys.stdout
sys.stdout = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
@contextmanager
def capture_stderr():
old_stderr = sys.stderr
sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stderr = old_stderr
@contextmanager
def capture_output():
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
class Tee(io.StringIO):
"""Sichtbare Ausgabe und gleichzeitige Erfassung."""
def __init__(self, original):
super().__init__()
self.original = original
def write(self, text):
self.original.write(text)
super().write(text)
def flush(self):
self.original.flush()
@contextmanager
def capture_stdout_tee():
old_stdout = sys.stdout
sys.stdout = tee = Tee(old_stdout)
try:
yield tee
finally:
sys.stdout = old_stdout
# ==========================
# Teil 3: Klassenbasierter Kontextmanager
# ==========================
class OutputCapture:
"""Klassenbasierter Kontextmanager zum Erfassen von stdout."""
def __init__(self):
self._buffer = io.StringIO()
self._old_stdout = None
def __enter__(self):
self._old_stdout = sys.stdout
sys.stdout = self._buffer
return self._buffer
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout = self._old_stdout
return False # Ausnahmen weitergeben
# ==========================
# Teil 4: Demonstrationen
# ==========================
def demo_classes():
print("\n--- Klassen-Demonstration ---")
dog = Dog()
cat = Cat()
print("Hund sagt:", dog.speak())
print("Katze sagt:", cat.speak())
my_car = Car('Toyota', 'Corolla', 2020)
print("Autobeschreibung:", my_car.description())
my_car.set_make('Honda')
print("Aktualisierte Marke:", my_car.get_make())
point = Point(3, 4)
print("Punkt:", point)
def demo_context_managers():
print("\n--- Kontextmanager-Demonstration ---")
with my_context() as res:
print("Im Kontext:", res)
with capture_stdout() as out:
print("stdout erfasst")
print("Buffer:", out.getvalue().strip())
with capture_stderr() as err:
print("Geht zu stdout")
sys.stderr.write("Fehlermeldung\n")
print("Fehler:", err.getvalue().strip())
with capture_output() as out_all:
print("Stdout in kombinierter Erfassung")
sys.stderr.write("Stderr in kombinierter Erfassung\n")
print("Kombinierte Ausgabe:", out_all.getvalue().strip())
with capture_stdout_tee() as tee_out:
print("Ausgabe sichtbar UND erfasst mit Tee")
print("Tee Buffer:", tee_out.getvalue().strip())
with OutputCapture() as class_capture:
print("Erfassung mit klassenbasiertem Kontextmanager")
print("Buffer des Klassenmanagers:", class_capture.getvalue().strip())
# ==========================
# Hauptausführung
# ==========================
if name == "main":
demo_classes()
demo_context_managers()