Klassenfunktionen in Python verstehen

PythonPythonBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einleitung

In diesem Labor erhalten Sie ein praktisches Verständnis wichtiger objektorientierter Programmierkonzepte in Python. Wir werden Kapselung erkunden, indem wir mit privaten Attributen arbeiten und lernen, wie der Datenzugriff innerhalb von Klassen gesteuert wird.

Darüber hinaus werden Sie Vererbung implementieren, um Beziehungen zwischen Klassen zu schaffen, einschließlich der Übung von Mehrfachvererbung. Das Labor wird auch Polymorphie demonstrieren und zeigen, wie Objekte verschiedener Klassen auf denselben Methodenaufruf unterschiedlich reagieren können. Schließlich werden Sie die super()-Methode verwenden, um Vererbungsbeziehungen effektiv zu verwalten.

Kapselung mit privaten Attributen erkunden

In diesem Schritt werden wir das Konzept der Kapselung in der objektorientierten Programmierung mit Python untersuchen. Kapselung ist die Bündelung von Daten (Attributen) und Methoden, die auf den Daten operieren, zu einer einzigen Einheit, der Klasse. Sie beinhaltet auch die Einschränkung des direkten Zugriffs auf einige Komponenten eines Objekts, was eine Methode zur Verhinderung versehentlicher Datenänderungen darstellt.

In Python können wir anzeigen, dass ein Attribut privat sein soll, indem wir seinem Namen ein oder zwei Unterstriche voranstellen.

  • Ein Attribut, dem ein einzelner Unterstrich vorangestellt ist (_name), ist eine Konvention, die darauf hinweist, dass das Attribut für die interne Verwendung innerhalb der Klasse oder durch ihre Unterklassen bestimmt ist. Es kann immer noch von außerhalb der Klasse zugegriffen werden, ist aber ein Signal an andere Entwickler, dass sie es nicht direkt zugreifen oder ändern sollten.
  • Ein Attribut, dem zwei Unterstriche vorangestellt sind (__name), löst Name Mangling aus, was den direkten Zugriff von außerhalb der Klasse erschwert. Dies bietet eine stärkere Form der Privatsphäre, obwohl sie nicht absolut ist.

Für dieses Experiment verwenden wir die Konvention mit dem einzelnen Unterstrich (_name), um das Konzept privater Attribute zu demonstrieren und wie man darauf zugreift und sie über öffentliche Methoden modifiziert.

Erstellen Sie zunächst eine Python-Datei namens dog_cat.py in Ihrem ~/project-Verzeichnis mit der WebIDE. Öffnen Sie die Datei und fügen Sie den folgenden Code hinzu:

## File Name: dog_cat.py

## This class represents a collection of dogs, and instances of this class are specific dogs.
class Dog(object):
    def __init__(self, name):
        ## In Python, private attributes are indicated by starting with one or two underscores.
        ## Attributes starting with a single underscore indicate that external callers should not directly access them,
        ## but they can still be accessed.
        ## Attributes starting with two underscores cannot be directly accessed externally, but there are ways.
        self._name = name

    ## The private attribute _name cannot be directly accessed.
    ## Therefore, we need to define two methods to modify and get the attribute value.
    ## get_name is used to get the attribute value, and set_name is used to modify the attribute value.
    def get_name(self):
        return self._name

    def set_name(self, value):
        self._name = value

    ## This method is used to print the animal's sound.
    def say(self):
        ## Here, self._name is directly accessing the private attribute.
        ## This is allowed within the class, but not outside the class.
        print(self._name + ' is making sound wang wang wang...')

## This class represents a collection of cats, and instances of this class are specific cats.
class Cat(object):
    def __init__(self, name):
        self._name = name

    def get_name(self):
        return self._name

    def set_name(self, value):
        self._name = value

    def say(self):
        print(self._name + ' is making sound miao miao miao...')

Speichern Sie die Datei. Öffnen Sie nun ein Terminal in der WebIDE und führen Sie diesen Code aus, um zu sehen, wie Kapselung funktioniert. Wir werden Instanzen der Klassen Dog und Cat erstellen und mit ihren Attributen und Methoden interagieren.

Führen Sie im Terminal die folgenden Befehle aus:

python

Dadurch wird der interaktive Python-Interpreter gestartet. Importieren Sie dann die Klassen und erstellen Sie Instanzen:

from dog_cat import Dog, Cat

dog = Dog('Tom')
print(dog.get_name())
dog.set_name('Tony')
print(dog.get_name())

cat = Cat('Kitty')
cat.say()
print(cat._name) ## Although accessible, it's a convention not to access private attributes directly from outside the class.

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

Tom
Tony
Kitty is making sound miao miao miao...
Kitty

Dies zeigt, wie wir öffentliche Methoden (get_name und set_name) verwenden, um mit dem _name-Attribut zu interagieren, das privat sein soll. Obwohl Python die Privatsphäre für Attribute mit einem einzelnen Unterstrich nicht strikt erzwingt, ist dies eine starke Konvention, die befolgt werden sollte.

Vererbung mit Tierklassen implementieren

Im vorherigen Schritt haben wir Dog- und Cat-Klassen mit ähnlichen Attributen und Methoden erstellt. Dies ist ein häufiges Szenario, in dem Vererbung nützlich wird. Vererbung ermöglicht es einer Klasse (Kind- oder Unterklasse), Attribute und Methoden von einer anderen Klasse (Eltern- oder Oberklasse) zu erben. Dies fördert die Wiederverwendbarkeit von Code und hilft, Code hierarchisch zu organisieren.

In diesem Schritt erstellen wir eine Elternklasse namens Animal und lassen die Klassen Dog und Cat von ihr erben. Die Animal-Klasse wird die gemeinsamen Attribute und Methoden enthalten, die sowohl von Dog als auch von Cat geteilt werden.

Öffnen Sie die Datei dog_cat.py in Ihrem ~/project-Verzeichnis mit der WebIDE. Fügen Sie die folgende Animal-Klassendefinition am Anfang der Datei hinzu:

## File Name: dog_cat.py

class Animal:
    def __init__(self, name):
        self._name = name

    def get_name(self):
        return self._name

    def set_name(self, value):
        self._name = value

Ändern Sie nun die Definitionen der Klassen Dog und Cat, damit sie von der Klasse Animal erben. Dies geschieht, indem der Name der Elternklasse in Klammern nach dem Namen der Kindklasse angegeben wird, z. B. class Dog(Animal):. Da die Methoden __init__, get_name und set_name nun in der Klasse Animal definiert sind, können wir sie aus den Klassen Dog und Cat entfernen.

Ändern Sie die Klassen Dog und Cat in dog_cat.py wie folgt:

class Dog(Animal):
    def say(self):
        print(self._name + ' is making sound wang wang wang...')

class Cat(Animal):
    def say(self):
        print(self._name + ' is making sound miao miao miao...')

Die vollständige Datei dog_cat.py sollte nun wie folgt aussehen:

## File Name: dog_cat.py

class Animal:
    def __init__(self, name):
        self._name = name

    def get_name(self):
        return self._name

    def set_name(self, value):
        self._name = value

class Dog(Animal):
    def say(self):
        print(self._name + ' is making sound wang wang wang...')

class Cat(Animal):
    def say(self):
        print(self._name + ' is making sound miao miao miao...')

Speichern Sie die Datei. Testen wir nun die Vererbung. Öffnen Sie ein Terminal und führen Sie die folgenden Befehle aus:

python

Importieren Sie dann die Klassen und erstellen Sie Instanzen:

from dog_cat import Dog, Cat

dog = Dog('Tom')
print(dog.get_name())
dog.set_name('Tony')
print(dog.get_name())

cat = Cat('Kitty')
cat.say()

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

Tom
Tony
Kitty is making sound miao miao miao...

Wie Sie sehen können, können die Instanzen der Klassen Dog und Cat die Methoden __init__, get_name und set_name verwenden, obwohl wir sie aus diesen Klassen entfernt haben, da sie diese von der Klasse Animal geerbt haben. Dies demonstriert die Leistungsfähigkeit der Vererbung zur Reduzierung von Code-Duplizierung.

Mehrfachvererbung üben

In Python kann eine Klasse von mehreren Elternklassen erben. Dies wird als Mehrfachvererbung bezeichnet. Mehrfachvererbung ermöglicht es einer Klasse, Attribute und Methoden von mehr als einer Basisklasse zu erben und Funktionen aus verschiedenen Quellen zu kombinieren.

Bei der Verwendung von Mehrfachvererbung ist es wichtig, die Method Resolution Order (MRO) zu verstehen, die die Reihenfolge angibt, in der Python nach Methoden und Attributen in einer Klassenhierarchie sucht. Python verwendet den C3-Linearisierungsalgorithmus, um die MRO zu bestimmen.

Erstellen wir eine neue Python-Datei namens multiple_inheritance.py in Ihrem ~/project-Verzeichnis, um die Mehrfachvererbung zu demonstrieren. Öffnen Sie die Datei und fügen Sie den folgenden Code hinzu:

## File Name: multiple_inheritance.py

class A:
    a = 1
    b = 1
    def method_a(self):
        print("Method from class A")

class B:
    a = 2
    b = 2
    def method_b(self):
        print("Method from class B")

class C(A):
    a = 3
    c = 4
    def method_c(self):
        print("Method from class C")

class D(B, C):
    d = 4
    def method_d(self):
        print("Method from class D")

class E(C, B):
    pass

Speichern Sie die Datei. In diesem Beispiel erbt D sowohl von B als auch von C, und C erbt von A. E erbt ebenfalls von C und B, jedoch in einer anderen Reihenfolge.

Öffnen wir nun ein Terminal und führen Sie dieses Skript aus, um zu untersuchen, wie Attribute und Methoden in diesem Mehrfachvererbungs-Setup zugegriffen werden.

python multiple_inheritance.py

Nachdem Sie das Skript ausgeführt haben, interagieren wir im Python-Interpreter mit den Klassen, um die Auswirkung der Mehrfachvererbung und der MRO zu sehen.

python

Importieren Sie die Klassen:

from multiple_inheritance import A, B, C, D, E

Greifen wir nun auf einige Attribute zu und rufen einige Methoden auf:

print(D().a)
print(D().b)
print(D().d)
D().method_a()
D().method_b()
D().method_c()
D().method_d()

print(E().a)
print(E().b)
E().method_a()
E().method_b()
E().method_c()

Beobachten Sie die Ausgabe. Wenn Sie auf D().a zugreifen, sucht Python nach a in D. Es ist nicht vorhanden, also prüft es die Elternklassen in der Reihenfolge, die in der Vererbungsliste angegeben ist: zuerst B, dann C. Es findet a zuerst in B und gibt daher 2 aus. Ähnlich findet es für D().b zuerst b in B und gibt 2 aus.

Für E().a sucht Python in E, dann in C, dann in A. Es findet a zuerst in C und gibt 3 aus. Für E().b sucht es in E, dann in C, dann in A, dann in B. Es findet b in B und gibt 2 aus.

Um die Suchreihenfolge klarer zu verstehen, können Sie die Methode mro() einer Klasse verwenden. Sehen wir uns die MRO für die Klassen D und E an:

print(D.mro())
print(E.mro())

Die Ausgabe zeigt die Reihenfolge an, in der Python nach Methoden und Attributen sucht. Für D(B, C) ist die MRO typischerweise [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]. Für E(C, B) ist die MRO typischerweise [<class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]. Die genaue Ausgabe kann je nach Python-Version und Umgebung leicht variieren, aber die Reihenfolge Ihrer definierten Klassen sollte konsistent sein.

Das Verständnis der MRO ist entscheidend, wenn Sie mit Mehrfachvererbung arbeiten, um vorherzusagen, auf welche Methode oder welches Attribut zugegriffen wird, wenn es Konflikte in den Elternklassen gibt.

Polymorphie demonstrieren

Polymorphie ist ein weiteres grundlegendes Konzept in der objektorientierten Programmierung. Es bedeutet "viele Formen" und bezieht sich auf die Fähigkeit verschiedener Objekte, auf denselben Methodenaufruf auf ihre eigene Weise zu reagieren. Im Kontext der Vererbung ermöglicht Polymorphie einer Unterklasse, eine spezifische Implementierung einer Methode bereitzustellen, die bereits in ihrer Oberklasse definiert ist. Dies wird als Methodenüberschreibung (method overriding) bezeichnet.

In unserem dog_cat.py-Beispiel haben sowohl die Klassen Dog als auch Cat eine say()-Methode, aber sie erzeugen unterschiedliche Ausgaben (unterschiedliche Geräusche). Dies ist ein Beispiel für Polymorphie. Obwohl sie beide Animals sind, haben sie ihre eigene spezifische Art, etwas zu "sagen".

Lassen Sie uns die Animal-Klasse in dog_cat.py ändern, damit sie ebenfalls eine say()-Methode hat. Öffnen Sie dog_cat.py in der WebIDE und fügen Sie die say()-Methode zur Animal-Klasse hinzu:

## File Name: dog_cat.py

class Animal:
    def __init__(self, name):
        self._name = name

    def get_name(self):
        return self._name

    def set_name(self, value):
        self._name = value

    def say(self):
        print(self._name + ' is saying something')

class Dog(Animal):
    def say(self):
        print(self._name + ' is making sound wang wang wang...')

class Cat(Animal):
    def say(self):
        print(self._name + ' is making sound miao miao miao...')

Speichern Sie die Datei. Erstellen wir nun Instanzen und rufen die say()-Methode auf.

Öffnen Sie ein Terminal und führen Sie die folgenden Befehle aus:

python

Importieren Sie die Klassen:

from dog_cat import Animal, Dog, Cat

Erstellen Sie Instanzen jeder Klasse und rufen Sie die say()-Methode auf:

animal = Animal('Generic Animal')
dog = Dog('Buddy')
cat = Cat('Whiskers')

animal.say()
dog.say()
cat.say()

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

Generic Animal is saying something
Buddy is making sound wang wang wang...
Whiskers is making sound miao miao miao...

Beachten Sie, dass, obwohl wir denselben Methodennamen (say()) für verschiedene Objekte (animal, dog, cat) aufrufen, die Ausgabe unterschiedlich ist, da jede Klasse ihre eigene Implementierung der say()-Methode bereitstellt. Dies ist Polymorphie in Aktion. Die spezifische Methode, die aufgerufen wird, hängt vom Typ des Objekts ab.

Polymorphie ist ein mächtiges Konzept, das es Ihnen ermöglicht, flexibleren und wiederverwendbaren Code zu schreiben. Sie können Funktionen schreiben, die mit Objekten eines Oberklassentyps arbeiten, und diese Funktionen verwenden automatisch die entsprechende Methodenimplementierung des spezifischen Unterklassenobjekts, das übergeben wird.

Die super()-Methode nutzen

In den vorherigen Schritten haben wir gesehen, wie Vererbung es Unterklassen ermöglicht, Methoden von Elternklassen zu erben, und wie Polymorphie es Unterklassen ermöglicht, diese Methoden zu überschreiben. Manchmal möchten Sie beim Überschreiben einer Methode in einer Unterklasse immer noch die ursprüngliche Methode der Elternklasse aufrufen. Hier ist die super()-Methode sehr nützlich.

Die super()-Methode in Python wird verwendet, um auf die Elternklasse zu verweisen. Sie ermöglicht es Ihnen, Methoden der Elternklasse aus der Kindklasse heraus aufzurufen. Dies ist besonders nützlich in der __init__()-Methode einer Unterklasse, wenn Sie sicherstellen möchten, dass auch die Initialisierung der Elternklasse durchgeführt wird.

Lassen Sie uns unsere dog_cat.py-Datei ändern, um die Verwendung von super() zu demonstrieren. Wir werden der Dog-Klasse ein age-Attribut und der Cat-Klasse ein color-Attribut hinzufügen und diese in ihren jeweiligen __init__()-Methoden initialisieren, während wir gleichzeitig die __init__()-Methode der Elternklasse Animal mithilfe von super() aufrufen.

Öffnen Sie dog_cat.py in der WebIDE und ändern Sie die Klassen Dog und Cat wie folgt:

## File Name: dog_cat.py

class Animal:
    def __init__(self, name):
        self._name = name

    def get_name(self):
        return self._name

    def set_name(self, value):
        self._name = value

    def say(self):
        print(self._name + ' is saying something')

class Dog(Animal):
    def __init__(self, name, age):
        ## Verwenden Sie super(), um die __init__-Methode der Elternklasse (Animal) aufzurufen
        super().__init__(name)
        self.age = age

    def say(self):
        print(self._name + ' is making sound wang wang wang...')
        print(f"I am {self.age} years old.") ## Altersinformation hinzufügen

class Cat(Animal):
    def __init__(self, name, color):
        ## Verwenden Sie super(), um die __init__-Methode der Elternklasse (Animal) aufzurufen
        super().__init__(name)
        self.color = color

    def say(self):
        print(self._name + ' is making sound miao miao miao...')
        print(f"My color is {self.color}.") ## Farbinformation hinzufügen

Speichern Sie die Datei. Testen wir nun die aktualisierten Klassen.

Öffnen Sie ein Terminal und führen Sie die folgenden Befehle aus:

python

Importieren Sie die Klassen:

from dog_cat import Dog, Cat

Erstellen Sie Instanzen von Dog und Cat mit den neuen Attributen und rufen Sie ihre Methoden auf:

dog = Dog('Buddy', 3)
print(dog.get_name())
print(dog.age)
dog.say()

cat = Cat('Whiskers', 'white')
print(cat.get_name())
print(cat.color)
cat.say()

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

Buddy
3
Buddy is making sound wang wang wang...
I am 3 years old.
Whiskers
white
Whiskers is making sound miao miao miao...
My color is white.

In den Klassen Dog und Cat haben wir die __init__()-Methode überschrieben. Durch die Verwendung von super().__init__(name) stellen wir sicher, dass die __init__()-Methode der Animal-Klasse weiterhin aufgerufen wird, was das _name-Attribut initialisiert. Anschließend fügen wir die spezifische Initialisierung für die Attribute age und color in den jeweiligen Unterklassen hinzu. Wir haben auch die say()-Methoden modifiziert, um die neuen Attribute einzuschließen, und zeigen so, wie Sie die Funktionalität von geerbten Methoden erweitern können.

Die super()-Methode ist unerlässlich für die Arbeit mit Vererbung, insbesondere bei der Initialisierung und Methodenüberschreibung, da sie es Ihnen ermöglicht, die Funktionalität der Elternklasse zu nutzen und gleichzeitig das Verhalten in der Unterklasse hinzuzufügen oder zu modifizieren.

Zusammenfassung

In diesem Lab haben wir grundlegende Konzepte der objektorientierten Programmierung in Python untersucht. Wir begannen mit dem Verständnis von Kapselung (encapsulation), indem wir zeigten, wie Daten mithilfe von privaten Attributen (angezeigt durch Unterstriche) geschützt und über öffentliche Methoden darauf zugegriffen werden kann.

Anschließend implementierten wir Vererbung, indem wir eine Hierarchie von Tierklassen erstellten und zeigten, wie Unterklassen Eigenschaften und Verhaltensweisen von Elternklassen erben. Wir übten auch Mehrfachvererbung (multiple inheritance), bei der eine Klasse von mehr als einer Elternklasse erbt. Schließlich demonstrierten wir Polymorphie (polymorphism), indem wir zeigten, wie Objekte verschiedener Klassen auf denselben Methodenaufruf auf ihre eigene Weise reagieren können, und nutzten die super()-Methode, um Methoden von einer Elternklasse aufzurufen.