Python-Klassen: Ein umfassender Leitfaden

vg
Python-Klassen

Python bietet Entwicklern als vielseitige und leistungsstarke Programmiersprache eine breite Palette an Werkzeugen, um robuste Anwendungen zu erstellen. Eines der grundlegendsten Konzepte in Python ist die Klasse, die als Blaupause für die Erstellung von Objekten dient. In diesem Artikel gehen wir ausführlich darauf ein, was Klassen sind, warum Sie möglicherweise eine eigene Klasse erstellen möchten, und untersuchen verschiedene Aspekte des Klassendesigns, einschließlich Methoden, Attribute, Vererbung und mehr.

1. Was ist eine Klasse?

Im Kern ist eine Klasse in Python eine Blaupause zum Erstellen von Objekten. Integrierte Datentypen wie Zeichenfolgen (), Ganzzahlen () und Listen () sind eigentlich Instanzen von Klassen. Wenn Sie eine Instanz einer Klasse erstellen, erstellen Sie im Wesentlichen ein Objekt, das der von der Klasse definierten Struktur folgt.strintlist

1.1 Warum eine eigene Klasse erstellen?

Wenn Sie eine eigene Klasse erstellen, können Sie benutzerdefinierte Datentypen und Verhaltensweisen definieren, die für Ihre Anwendung spezifisch sind. Dies ist besonders nützlich, wenn:

  • Modellierung komplexer Entitäten: Wenn Sie mit realen Konzepten wie , oder arbeiten, können Sie durch die Definition einer Klasse alle relevanten Eigenschaften und Verhaltensweisen kapseln.CarPersonBankAccount
  • Wiederverwendbarkeit: Durch das Erstellen einer Klasse können Sie dieselbe Logik in verschiedenen Teilen des Programms wiederverwenden, ohne Code zu duplizieren. Wenn Sie z. B. über eine Klasse verfügen, die die Benutzerauthentifizierung verarbeitet, können Sie sie an mehreren Stellen in der Anwendung verwenden, ohne jedes Mal dieselbe Logik neu schreiben zu müssen.
  • Verkapselung: Klassen ermöglichen es Ihnen, verwandte Daten (Attribute) und Verhaltensweisen (Methoden) miteinander zu bündeln, wodurch Ihr Code einfacher zu verwalten und zu verstehen ist. Die Kapselung trägt auch dazu bei, den internen Zustand eines Objekts zu schützen, indem der direkte Zugriff auf einige seiner Komponenten eingeschränkt wird.

Stellen Sie sich einen Kurs als Blaupause für eine Art von Sache vor, die Sie in Ihrem Programm darstellen möchten. Wenn Sie z. B. eine modellieren, kann Ihre Klasse Attribute wie , und , zusammen mit Methoden wie oder enthalten. Hier ist ein einfaches Beispiel:Carmakemodelyearstart_engine()accelerate()

class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year

def start_engine(self):
print(f"The {self.year} {self.make} {self.model}'s engine has started.")

def accelerate(self, speed_increase):
print(f"The car accelerates by {speed_increase} mph.")

In diesem Beispiel kapselt die Klasse sowohl die Daten (Marke, Modell, Jahr) als auch das Verhalten (Starten des Motors, Beschleunigen). Sie können mehrere Instanzen dieser Klasse erstellen, die jeweils ein anderes Auto mit eigenen einzigartigen Attributen darstellen.Car

2. Methoden vs. Funktionen

In Python sind sowohl Methoden als auch Funktionen Codeblöcke, die zum Ausführen von Aktionen entwickelt wurden, sich jedoch in ihrer Zuordnung unterscheiden:

  • Funktionen sind eigenständige Codeblöcke, die mithilfe des Schlüsselworts definiert werden. Sie arbeiten unabhängig voneinander und gehören nicht von Natur aus zu einer Klasse oder einem Objekt. Zum Beispiel:def
def greet(name):
return f"Hello, {name}!"

Diese Funktion kann von einer beliebigen Stelle im Code aufgerufen werden, unabhängig davon, ob sie sich in einer Klasse befindet oder nicht.

  • Methoden hingegen sind Funktionen, die innerhalb einer Klasse definiert sind. Sie arbeiten mit den Instanzen (Objekten) dieser Klasse. Wenn Sie eine Methode aufrufen, übergibt Python automatisch die Instanz selbst als erstes Argument, das in der Regel den Namen .self
class Person:
def __init__(self, name):
self.name = name

def greet(self):
return f"Hello, my name is {self.name}."

Hier ist eine Methode, die auf der Instanz arbeitet. Der Parameter ermöglicht es der Methode, auf die Attribute der Instanz und andere Methoden zuzugreifen. Wenn Sie eine Instanz von erstellen und die Methode aufrufen, übergibt Python die Instanz implizit als erstes Argument:greetselfselfPersongreet

person = Person("Alice")
print(person.greet()) # Output: Hello, my name is Alice.

Zusammenfassend lässt sich sagen, dass der Hauptunterschied zwischen einer Funktion und einer Methode das Vorhandensein des Parameters in Methoden ist, wodurch sie direkt an eine Instanz einer Klasse gebunden sind.self

3. Die Methode: Initialisieren von Objekten__init__

Die Methode __init__, die auch als Konstruktor bezeichnet wird, ist eine spezielle Methode, die automatisch aufgerufen wird, wenn Sie eine Instanz einer Klasse erstellen. Es wird verwendet, um die Attribute des Objekts zu initialisieren.

Die Methode nimmt immer das erste Argument an, gefolgt von allen zusätzlichen Parametern, die Sie definieren. Diese Parameter können verwendet werden, um Anfangswerte für die Attribute des Objekts festzulegen.__init__self

class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year

def display_info(self):
return f"{self.year} {self.make} {self.model}"

my_car = Car("Toyota", "Corolla", 2020)
print(my_car.display_info()) # Output: 2020 Toyota Corolla

In diesem Beispiel verwendet die Methode drei Parameter (, , ) und weist sie Instanzattributen zu. Die Methode wird nur einmal ausgeführt, und zwar zum Zeitpunkt der Erstellung der Instanz.__init__makemodelyear__init__

Wichtige Punkte zu:__init__

  • Automatischer Aufruf: Die Methode wird automatisch aufgerufen, wenn Sie eine neue Instanz der Klasse mit der Syntax erstellen.__init__Class()
  • Initialisierung: Es ist der perfekte Ort, um die Attribute des Objekts zu initialisieren und den erforderlichen Zustand einzurichten, bevor das Objekt verwendet wird.
  • Mehrere Konstruktoren : Im Gegensatz zu einigen anderen Sprachen unterstützt Python nicht mehrere Konstruktoren direkt. Sie können jedoch eine ähnliche Funktionalität mit Standardargumenten oder Klassenmethoden erzielen.

4. Validieren von Daten im Konstruktor

Es ist häufig wichtig, die Daten zu überprüfen, die an den Konstruktor einer Klasse übergeben werden, um sicherzustellen, dass sich Objekte immer in einem gültigen Zustand befinden. Sie können dies mit assert-Anweisungen innerhalb der Methode __init__ tun.

Eine Anweisung überprüft, ob eine Bedingung wahr ist. Ist dies nicht der Fall, wird ein assertAssertionError ausgelöst, optional mit einer benutzerdefinierten Nachricht. Auf diese Weise können Sie Einschränkungen für die Daten erzwingen, die zum Erstellen neuer Objekte verwendet werden.

class Car:
def __init__(self, make, model, year):
assert isinstance(make, str), "Make must be a string"
assert isinstance(model, str), "Model must be a string"
assert isinstance(year, int) and year > 1885, "Year must be an integer greater than 1885"

self.make = make
self.model = model
self.year = year

In diesem Beispiel erzwingen Anweisungen Einschränkungen für die Eingabedaten. Wenn eine Bedingung fehlschlägt, wird ein assertAssertionError mit einer benutzerdefinierten Meldung ausgelöst. Zum Beispiel:

car = Car("Toyota", "Corolla", 2020)  # This works fine

# This will raise an AssertionError because the year is not an integer
car = Car("Toyota", "Corolla", "2020") # AssertionError: Year must be an integer greater than 1885

Fortgeschrittene Validierungstechniken:

  • Benutzerdefinierte Fehlermeldungen: Sie können benutzerdefinierte Fehlermeldungen bereitstellen, um das Debuggen zu vereinfachen.
  • Typhinweise: Obwohl sie zur Laufzeit nicht erzwungen werden, können Typhinweise bei statischen Analysetools hilfreich sein und die Lesbarkeit des Codes verbessern.
  • Eingabebereinigung : Manchmal möchten Sie Eingabedaten bereinigen, bevor Sie sie Attributen zuweisen. Zum Beispiel das Konvertieren von Zeichenfolgen in Kleinbuchstaben oder das Entfernen von Leerzeichen.

5. Klassenattribute vs. Instanzattribute

Klassenattribute und Instanzattribute dienen unterschiedlichen Zwecken:

  • Klassenattribute werden von allen Instanzen einer Klasse gemeinsam genutzt. Sie werden außerhalb von Methoden definiert und können über den Klassennamen oder über eine beliebige Instanz der Klasse aufgerufen werden.
  • Instanzattribute sind für jedes Objekt eindeutig und werden in der Regel in Methoden wie __init__ definiert.

Hier ist ein Beispiel, das den Unterschied veranschaulicht:

class Car:
wheels = 4 # Class attribute

def __init__(self, make, model, year):
self.make = make # Instance attribute
self.model = model # Instance attribute
self.year = year # Instance attribute

car1 = Car("Toyota", "Corolla", 2020)
car2 = Car("Honda", "Civic", 2021)

print(Car.wheels) # Output: 4
print(car1.wheels) # Output: 4
print(car2.wheels) # Output: 4

# Modifying the class attribute affects all instances
Car.wheels = 6
print(car1.wheels) # Output: 6
print(car2.wheels) # Output: 6

# Modifying an instance attribute only affects that instance
car1.wheels = 3
print(car1.wheels) # Output: 3
print(car2.wheels) # Output: 6

Wichtige Punkte:

  • Shared State: Klassenattribute werden von allen Instanzen der Klasse gemeinsam genutzt. Das Ändern eines Klassenattributs über die Klasse selbst wirkt sich auf alle Instanzen aus, es sei denn, es wird für eine bestimmte Instanz überschrieben.
  • Eindeutiger Zustand: Instanzattribute sind für jedes Objekt eindeutig. Änderungen an einem Instanzattribut wirken sich nur auf diese bestimmte Instanz aus.
  • Best Practices: Verwenden Sie Klassenattribute für Konstanten oder Standardwerte, die von allen Instanzen gemeinsam genutzt werden sollten. Verwenden Sie Instanzattribute für Daten, die von Objekt zu Objekt unterschiedlich sind.

6. Statische Methoden, Klassenmethoden und reguläre Methoden

Python bietet drei Arten von Methoden innerhalb einer Klasse:

  • Statische Methoden sind Funktionen, die innerhalb einer Klasse definiert sind, aber nicht an eine bestimmte Instanz oder die Klasse selbst gebunden sind. Sie werden mit dem Decorator @staticmethod definiert und verfügen nicht über den impliziten self oder cls Parameter. Sie werden häufig für Hilfsfunktionen verwendet.
class MathUtils:
@staticmethod
def add(a, b):
return a + b

result = MathUtils.add(5, 3) # Output: 8

In diesem Beispiel handelt es sich bei der Methode add um eine statische Methode, da sie nicht auf instanzspezifische Daten zugreifen muss. Es führt einfach eine Berechnung durch und gibt das Ergebnis zurück.

  • Klassenmethoden werden mit Hilfe des Decorators @classmethod definiert und erhalten als ersten Parameter cls die Klasse self(). Sie können verwendet werden, um Instanzen auf alternative Weise zu erstellen.
class Car:
wheels = 4

def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year

@classmethod
def from_string(cls, car_str):
make, model, year = car_str.split('-')
return cls(make, model, int(year))

car = Car.from_string("Toyota-Corolla-2020")
print(car.make) # Output: Toyota

In diesem Beispiel können Sie mit der class-Methode eine Instanz aus einer formatierten Zeichenfolge erstellen. Der Parameter bezieht sich auf die Python-Klassen selbst und ermöglicht es Ihnen, die Methode der Klasse aufzurufen, um eine neue Instanz zu erstellen.from_stringCarcls__init__

  • Reguläre Methoden erhalten die Instanz self() als ersten Parameter und werden verwendet, um mit den Attributen der Instanz zu arbeiten.
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year

def display_info(self):
return f"{self.year} {self.make} {self.model}"

In diesem Beispiel handelt es sich bei der Methode display_info um eine reguläre Methode, die mit den Attributen der Instanz arbeitet.

Wann sollten die einzelnen Typen verwendet werden?

  • Statische Methoden: Verwenden Sie diese Option, wenn die Methode nicht auf instanzspezifische Daten zugreifen muss und unabhängig arbeiten kann.
  • Methoden der Klasse: Verwenden Sie diese Option, wenn Sie Instanzen auf alternative Weise erstellen müssen oder wenn die Methode auf Daten auf Klassenebene zugreifen oder diese ändern muss.
  • Reguläre Methoden: Verwenden Sie diese Option, wenn die Methode auf instanzspezifische Daten zugreifen oder diese ändern muss.

Erstellen von schreibgeschützten Attributen

Manchmal möchten Sie bestimmte Attribute nach der Initialisierung schreibgeschützt machen. Dies kann mit dem Dekorator @property erreicht werden.

Mit dem Decorator @property können Sie eine Methode definieren, die sich wie ein Attribut verhält. Das bedeutet, dass Sie mithilfe der Punktnotation auf den Wert des Attributs zugreifen, ihn jedoch nicht direkt ändern können.

class Car:
def __init__(self, make, model, year):
self._make = make # Private attribute
self._model = model # Private attribute
self._year = year # Private attribute

@property
def make(self):
return self._make

@property
def model(self):
return self._model

@property
return self._year

car = Car("Toyota", "Corolla", 2020)
print(car.make) # Output: Toyota

# Attempting to modify the attribute will raise an AttributeError
# car.make = "Honda" # AttributeError: can't set attribute

In diesem Beispiel sind die Attribute make, model und year schreibgeschützt. Der Decorator @property ermöglicht es Ihnen, auf diese Attribute mithilfe der Punktnotation zuzugreifen, aber Sie können sie nicht direkt ändern.

Erweiterte Verwendung:

  • Setter: Wenn Sie Änderungen unter bestimmten Bedingungen zulassen möchten, können Sie mit dem Dekorator @attribute_name.setter eine Setter-Methode definieren.
class Car:
def __init__(self, make, model, year):
self._make = make
self._model = model
self._year = year

@property
def make(self):
return self._make

@make.setter
def make(self, value):
if isinstance(value, str):
self._make = value
else:
raise ValueError("Make must be a string")

car = Car("Toyota", "Corolla", 2020)
car.make = "Honda" # This works fine
# car.make = 123 # Raises ValueError: Make must be a string

7. Vererbung und Polymorphismus

Die Vererbung ermöglicht es einer Klasse, Attribute und Methoden von einer anderen Klasse zu erben, die als übergeordnete Klasse oder Oberklasse bezeichnet wird. Die Klasse, die von der übergeordneten Klasse erbt, wird als untergeordnete Klasse oder Unterklasse bezeichnet.

Die Vererbung fördert die Wiederverwendung von Code und ermöglicht es Ihnen, hierarchische Beziehungen zwischen Klassen aufzubauen. Angenommen, Sie verfügen über eine BasisklasseVehicle, die allgemeine Attribute und Methoden für alle Fahrzeuge definiert, und erstellen dann Unterklassen wie Vehicle, Car, Truck und Bike, die von ihren eigenen spezifischen Attributen und Methoden erben und diese hinzufügen.

class Vehicle:
def __init__(self, brand, year):
self.brand = brand
self.year = year

def start(self):
print(f"{self.brand} vehicle started.")

class Car(Vehicle):
def __init__(self, brand, year, model):
super().__init__(brand, year)
self.model = model

def start(self):
print(f"{self.brand} {self.model} car started.")

my_car = Car("Toyota", 2020, "Corolla")
my_car.start() # Output: Toyota Corolla car started.

In diesem Beispiel erbt die Klasse Car von der Klasse Vehicle. Es ruft die Methode __init__ der übergeordneten Klasse super() auf, um die geerbten Attribute ( brand und year) zu initialisieren. Die Klasse Car überschreibt auch die Methode start, um eine eigene Implementierung bereitzustellen.

Polymorphismus

Polymorphismus bezieht sich auf die Fähigkeit verschiedener Python-Klassen, dieselbe Schnittstelle auf unterschiedliche Weise zu implementieren. Im obigen Beispiel haben beide Vehicle und Car eine Methode start, verhalten sich jedoch je nach Klasse unterschiedlich.

Polymorphismus ermöglicht es Ihnen, flexibleren und generischeren Code zu schreiben. Sie können z. B. eine Funktion haben, die jede Art von Vehicle akzeptiert und ihre Methode start aufruft, ohne den spezifischen Fahrzeugtyp kennen zu müssen.

def start_vehicle(vehicle):
vehicle.start()

vehicle1 = Vehicle("Generic Brand", 2019)
vehicle2 = Car("Toyota", 2020, "Corolla")

start_vehicle(vehicle1) # Output: Generic Brand vehicle started.
start_vehicle(vehicle2) # Output: Toyota Corolla car started.

Hauptvorteile von Vererbung und Polymorphismus:

  • Codewiederverwendung: Die Vererbung ermöglicht die Wiederverwendung von Code aus vorhandenen Klassen, wodurch Duplikate reduziert und die Wartbarkeit verbessert werden.
  • Flexibilität : Polymorphismus ermöglicht es Ihnen, flexibleren und generischeren Code zu schreiben, der mit verschiedenen Arten von Objekten arbeiten kann.
  • Hierarchische Organisation: Die Vererbung ermöglicht es Ihnen, Ihre Klassen hierarchisch zu organisieren, was die Verwaltung großer Codebasen erleichtert.

Fazit

Python-Klassen sind eine leistungsstarke Funktion in Python, mit der Sie benutzerdefinierte Datentypen erstellen, Verhalten kapseln und wieder verwendbaren Code erstellen können. Wenn Sie wissen, wie Sie Klassen definieren, mit Methoden arbeiten, Attribute verwalten und Vererbung und Polymorphie nutzen, können Sie modularere, wartbarere und skalierbarere Programme schreiben.

Weiterer lesenswerter Beitrag finden Sie hier: Die SOLID-Prinzipien: Skalierbarer und wartbarer Code

com

Newsletter Anmeldung

Bleiben Sie informiert! Wir informieren Sie über alle neuen Beiträge (max. 1 Mail pro Woche – versprochen)