Kl

Klassen in Python

49 Übungen

Über Klassen

Classes kombinieren Daten mit Verhalten. Klassen werden verwendet, um Kopien oder instances gebündelter Daten und Verhaltens zu erstellen, gemeinhin als objects bekannt. Objekte können reale Dinge (wie Autos oder Katzen) oder abstraktere Konzepte (wie Ganzzahlen, Fahrzeuge oder Säugetiere) darstellen. Klassen sind wesentlicher Bestandteil eines objektorientierten Programmieransatzes (OOP). Dabei modellierst du ein Problem als ein oder mehrere Objekte, die miteinander interagieren, einen Zustand behalten und auf Daten einwirken.

Klassen

Klassen sind die Definitionen neuer Objekttypen, aus denen neue instances von Objekten erzeugt werden. Sie bündeln oft Daten (bekannt als fields, attributes, properties, data members oder variables) mit Code oder Funktionen (bekannt als methods), die auf diesen Daten arbeiten. In diesem Sinn ist eine Klasse ein Bauplan oder eine Sammlung von Anweisungen, nach denen viele Objekte ähnlichen Typs gebaut und verwendet werden können. Ein komplexes Programm kann viele Klassen haben, die jeweils viele verschiedene Arten von Objekten erzeugen. Der Vorgang, ein Objekt aus einer Klasse zu bauen und anzupassen, heißt instantiation (oder: eine Instanz der Klasse erzeugen).

Eine Klassendefinition in Python ist unkompliziert:

class MyClass:
    # Class body goes here

Klassenattribute

Klassenfelder (auch bekannt als Eigenschaften, Attribute, Datenmitglieder oder Variablen) können in den Rumpf der Klasse eingefügt werden.

class MyClass:
    number = 5
    string = "Hello!"

Eine Instanz (ein Objekt) von MyClass kann erzeugt und an einen Namen gebunden werden:

>>> new_object = MyClass()

# Class is instantiated and resulting object is bound to the "new_object" name (variable).
# Note: the object address 'at 0x15adc55b0' will vary by computer.
>>> new_object
<__main__.MyClass at 0x15adc55b0>

Class attributes werden von allen Objekten (oder Instanzen) geteilt, die aus einer Klasse erzeugt werden, und sind über dot notation erreichbar, also über ein . nach dem Objektnamen und vor dem Attributnamen:

>>> new_object = MyClass()

# Accessing the class attribute "number" via dot-notation.
>>> new_object.number
5

# Accessing the class attribute "string" via dot-notation.
>>> new_object.string
'Hello!'

# Instantiating an additional object and binding it to the "second_new_object" name.
>>> second_new_object = MyClass()

>>> second_new_object
<__main__.MyClass at 0x15ad99970>

# Second_new_object shares the same class attributes as new_object.
>>> new_object.number == second_new_object.number
True

Klassenattribute werden im Rumpf der Klasse selbst definiert, vor allen anderen Methoden. Sie gehören der Klasse, wodurch sie von allen Instanzen gemeinsam genutzt werden können. Da diese Attribute von allen Instanzen der Klasse geteilt werden, kann von der Klasse direkt auf ihren Wert zugegriffen und er geändert werden. Wenn du den Wert von Klassenattributen änderst, änderst du den Wert für alle Objekte, die aus der Klasse instanziiert wurden:

>>> obj_one = MyClass()
>>> obj_two = MyClass()

# Accessing a class attribute from an object.
>>> obj_two.number
5

# Accessing the class attribute from the class itself.
>>> MyClass.number
5

# Modifying the value of the "number" class attribute.
>>> MyClass.number = 27

# Modifying the "number" class attribute changes the "number" attribute for all objects.
>>> obj_one.number
27

>>> obj_two.number
27

Eine Menge Objekte, deren Daten ständig synchron sind, ist nicht besonders nützlich. Zum Glück kannst du Objekte, die aus einer Klasse erzeugt werden, mit eigenen instance attributes (oder Instanzeigenschaften, -variablen oder -feldern) anpassen. Wie der Name schon sagt, sind Instanzattribute für jedes Objekt einzigartig und können unabhängig voneinander geändert werden.

Objektinstanziierung mit __init__() anpassen

Die spezielle „Dunder-Methode“ (kurz für „double underscore method“) __init__() wird verwendet, um Klasseninstanzen anzupassen, und kann genutzt werden, um Instanzattribute oder -eigenschaften von Objekten zu initialisieren. Weil sie Instanzattribute initialisiert, wird __init__() auch als class constructor oder initializer bezeichnet. __init__() nimmt einen erforderlichen Parameter namens self entgegen, der auf das neu initialisierte oder erzeugte Objekt verweist. Daten für Instanzattribute oder -eigenschaften kannst du dann als Argumente von __init__() übergeben, nach dem Parameter self.

Unten hat MyClass nun Instanzattribute namens location_x und location_y. Wie du siehst, wurden die beiden Attribute dem ersten und zweiten Index des location-Arguments (ein Tupel) zugewiesen, das an __init__() übergeben wurde. Die Attribute location_x und location_y einer Klasseninstanz werden nun initialisiert, wenn du die Klasse instanziierst und ein Objekt erzeugt wird:

class MyClass:
    # These are class attributes, variables, or fields.
    number = 5
    string = "Hello!"

    # This is the class "constructor", with a "location" parameter that is a tuple.
    def __init__(self, location):

        # This is an instance or object property, attribute, or variable.
        # Note that we are unpacking the tuple argument into two separate instance variables.
        self.location_x = location[0]
        self.location_y = location[1]

# Create a new object "new_object_one", with object property (1, 2).
>>> new_object_one = MyClass((1, 2))

# Create a second new object "new_object_two" with object property (-8, -9).
>>> new_object_two = MyClass((-8, -9))

# Note that new_object_one.location_x and new_object_two.location_x two different values.
>>> new_object_one.location_x
1

>>> new_object_two.location_x
-8

Beachte, dass du beim Initialisieren von MyClass oben nur ein Argument übergeben musst: Python kümmert sich darum, self zu übergeben, wenn die Klasse aufgerufen wird.

Advanced

Eine andere Möglichkeit, eine Instanzvariable zu erzeugen, ist, einfach über ein Objekt auf eine Klassenvariable zuzugreifen und sie auf etwas anderes zu ändern:

>>> obj_one = MyClass()
>>> obj_two = MyClass()
>>> MyClass.string
'Hello!'

>>> obj_two.string = "Hi!"
>>> obj_two.string
'Hi!'

>>> obj_one.string
'Hello!'

Schau nun, was passiert, wenn sich die Klassenvariable ändert:

>>> MyClass.string = "World!"
>>> obj_two.string

# obj_two.string has not changed
'Hi!'

>>> obj_one.string

# obj_one.string changed
'World!'

Das Attribut string ist im Fall von obj_two nun eine Instanzvariable, bleibt in obj_one aber eine Klassenvariable.

Das geht auch von innerhalb der Klasse:

class Demo:
    new_var = 3

    def add_two(self):
        self.new_var += 2

In dem Moment, in dem <object>.add_two() aufgerufen und self.new_var += 2 ausgeführt wird, wird new_var von einer Klassenvariablen zu einer Instanzvariablen desselben Namens.

Das kann bei der Initialisierung nützlich sein, wenn alle Instanzen einer Klasse mit demselben Wert für bestimmte Attribute starten sollen. Allerdings verdeckt die Instanzvariable dann die Klassenvariable, wodurch die Klassenvariable von der Instanz aus nicht mehr erreichbar ist, in der sie verdeckt wird. In dieser Situation ist es möglicherweise sicherer und klarer, Instanzattribute in der Methode __init__() als self.<attribute> zu setzen.

Methoden

Eine method ist eine function, die entweder an die Klasse selbst gebunden ist (bekannt als Klassenmethode, die in einer späteren Übung ausführlich behandelt wird) oder an eine Instanz der Klasse (ein Objekt). Methoden, die auf einem Objekt oder einer Instanz arbeiten, müssen mit self als erstem Parameter definiert werden. Die übrigen Parameter definierst du dann wie bei einer „normalen“ oder nicht gebundenen Funktion. Methoden, die auf einer Klasse arbeiten, müssen mit dem Decorator @classmethod und (per Konvention) mit cls als erstem Parameter definiert werden. Klassenmethoden werden direkt auf einer Klasse aufgerufen, ohne zuvor ein Objekt aus der Klasse zu erzeugen.

class MyClass:
    number = 5
    string = "Hello!"

    # Class constructor.
    def __init__(self, location):

        # Instance properties
        self.location_x = location[0]
        self.location_y = location[1]

    # Class method. Uses the @classmethod decorator, and cls as the first parameter.
    # Can be called without first making an instance of the class.
    @classmethod
    def change_string(cls, new_string):
        #Class attributes are referred to with cls.
        cls.string = new_string
        return cls.string

    # Instance method.  Note "self" as first parameter.
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

Wie beim Zugriff auf Attribute ist das Aufrufen einer Methode so einfach wie ein . nach dem Objektnamen und vor dem Methodennamen. Die aufgerufene Methode braucht keine Kopie des Objekts als ersten Parameter: Python füllt self automatisch ein:

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

# Make a new test_object with location (3,7)
>>> test_object = MyClass((3,7))
>>> (test_object.location_x, test_object.location_y)
(3,7)

# Call change_location to increase location_x and location_y by 7.
>>> test_object.change_location(7)
(10, 14)

Auf Klassenattribute kann aus Instanzmethoden genauso zugegriffen werden wie von außerhalb der Klasse:

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    # Alter instance variable location_x and location_y
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

    # Alter class variable number for all instances from within an instance.
    def increment_number(self):
        # Increment the 'number' class variable by 1.
        MyClass.number += 1


>>> test_object_one = MyClass((0,0))
>>> test_object_one.number
5

>>> test_object_two = MyClass((13, -3))
>>> test_object_two.increment_number()
>>> test_object_one.number
6

Implementierung mit pass vorläufig ersetzen oder stubben

In früheren Konzeptübungen und den Stubs von Übungsaufgaben hast du gesehen, wie das Schlüsselwort pass im Rumpf von Funktionen anstelle von echtem Code verwendet wird.

Das Schlüsselwort pass ist ein syntaktisch gültiger Platzhalter: Es verhindert, dass Python bei einer leeren Funktions- oder Klassendefinition einen Syntaxfehler wirft. Im Grunde sagst du damit dem Python-Interpreter: „Keine Sorge! Ich werde hier irgendwann Code einfügen, ich bin nur noch nicht dazu gekommen.“

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    # Alter instance variable location_x and location_y.
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return  self.location_x, self.location_y

    # Alter class variable number for all instances.
    def increment_number(self):
        # Increment the 'number' class variable by 1.
        MyClass.number += 1

    # This will compile and run without error, but has no current functionality.
    def pending_functionality(self):
       # Stubbing or place-holding the body of this method.
       pass
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab

Lerne Klassen

Das Üben ist gesperrt

Schalte 6 weitere Übungen frei, um Klassen zu üben