In diesem Artikel werden Sie eine Anwendung für das Einmaleins erstellen, indem Sie die Möglichkeiten der objektorientierten Programmierung (OOP) in Python nutzen
Sie werden die wichtigsten Konzepte der O.O.P. kennenlernen und erfahren, wie Sie diese in einer voll funktionsfähigen Anwendung einsetzen können
Python ist eine multiparadigmatische Programmiersprache, was bedeutet, dass wir als Entwickler für jede Situation und jedes Problem die beste Option wählen können. Wenn wir von objektorientierter Programmierung sprechen, beziehen wir uns auf eines der in den letzten Jahrzehnten am häufigsten verwendeten Paradigmen zur Erstellung skalierbarer Anwendungen
Die Grundlagen von OOP
Werfen wir einen kurzen Blick auf das wichtigste Konzept der O.O.P in Python: die Klassen
Eine Klasse ist eine Vorlage, in der wir die Struktur und das Verhalten von Objekten definieren. Diese Vorlage ermöglicht es uns, Instanzen zu erstellen, die nichts anderes als individuelle Objekte sind, die nach der Zusammensetzung der Klasse erstellt werden
Eine einfache Buchklasse mit den Attributen Titel und Farbe würde wie folgt definiert werden
class Book:
def __init__(self, title, color):
self.title = title
self.color = color
Wenn wir Instanzen der Klasse Book erstellen wollen, müssen wir die Klasse aufrufen und ihr Argumente übergeben
#
Instanzobjekte der Klasse Book
blue_book = Book("Das blaue Kind", "Blau")
green_book = Book("Die Froschgeschichte", "Grün")
Eine gute Darstellung unseres aktuellen Programms wäre
Das Tolle ist, dass wir, wenn wir den Typ der Instanzen von blue_book und green_book überprüfen, “Book” erhalten
#
Drucken des Typs der Bücher
print(type(blue_book))
#
<class '__main__.Book'>
print(type(green_book))
#
<class '__main__.Book'>
Nachdem wir uns über diese Konzepte im Klaren sind, können wir mit der Erstellung des Projekts beginnen 😃
Projekt-Anweisung
Wenn wir als Entwickler/Programmierer arbeiten, verbringen wir die meiste Zeit nicht mit dem Schreiben von Code. Laut thenewstack verbringen wir nur ein Drittel unserer Zeit mit dem Schreiben oder Refactoring von Code
Die anderen zwei Drittel verbringen wir damit, den Code anderer zu lesen und das Problem zu analysieren, an dem wir gerade arbeiten
Für dieses Projekt werde ich also eine Problemstellung erstellen und wir werden analysieren, wie wir daraus unsere App erstellen können. So machen wir den kompletten Prozess durch, vom Nachdenken über die Lösung bis zur Anwendung mit Code
Ein Grundschullehrer möchte ein Spiel, um die Multiplikationsfähigkeiten von Schülern im Alter von 8 bis 10 Jahren zu testen.
Das Spiel muss ein Lebens- und ein Punktesystem haben, bei dem der Schüler mit 3 Leben beginnt und eine bestimmte Anzahl von Punkten erreichen muss, um zu gewinnen. Das Programm muss eine “Verloren”-Meldung anzeigen, wenn der Schüler alle seine Leben aufgebraucht hat.
Das Spiel muss über zwei Modi verfügen: Zufallsmultiplikationen und Tabellenmultiplikationen.
Im ersten Modus muss der Schüler eine zufällige Multiplikation von 1 bis 10 erhalten, die er richtig beantworten muss, um einen Punkt zu gewinnen. Wenn das nicht der Fall ist, verliert der Schüler einen Punkt und das Spiel geht weiter. Der Schüler gewinnt erst, wenn er/sie 5 Punkte erreicht hat.
Im zweiten Modus wird eine Multiplikationstabelle von 1 bis 10 angezeigt, in die der Schüler das Ergebnis der jeweiligen Multiplikation eingeben muss. Wenn der Schüler 3 Mal scheitert, verliert er/sie, aber wenn er/sie zwei Tabellen vervollständigt, ist das Spiel beendet
Ich weiß, dass die Anforderungen vielleicht ein wenig größer sind, aber ich verspreche Ihnen, dass wir sie in diesem Artikel lösen werden 😁
Teilen und erobern
Die wichtigste Fähigkeit beim Programmieren ist das Lösen von Problemen. Sie müssen nämlich einen Plan haben, bevor Sie anfangen, sich in den Code einzuhacken
Ich schlage immer vor, ein größeres Problem zu nehmen und es in kleinere Probleme zu unterteilen, die sowohl einfach als auch effizient gelöst werden können
Wenn Sie also ein Spiel entwickeln müssen, beginnen Sie damit, es in die wichtigsten Teile zu zerlegen. Diese Teilprobleme werden viel leichter zu lösen sein
Erst dann haben Sie Klarheit darüber, wie Sie alles mit Code ausführen und integrieren können
Lassen Sie uns also eine Grafik erstellen, wie das Spiel aussehen würde
Diese Grafik stellt die Beziehungen zwischen den Objekten unserer App her. Wie Sie sehen können, sind die beiden Hauptobjekte die Zufallsmultiplikation und die Tabellenmultiplikation. Und das einzige, was sie gemeinsam haben, sind die Attribute Punkte und Leben
Mit all diesen Informationen im Hinterkopf können wir nun mit dem Code beginnen
Erstellen der Klasse Parent game
Wenn wir mit objektorientierter Programmierung arbeiten, suchen wir nach dem saubersten Weg, um Codewiederholungen zu vermeiden. Das nennt man DRY (don’t repeat yourself)
Hinweis: Dieses Ziel hat nichts damit zu tun, möglichst wenige Codezeilen zu schreiben (die Codequalität darf nicht an diesem Aspekt gemessen werden), sondern die am häufigsten verwendete Logik zu abstrahieren
Gemäß der vorherigen Idee muss die übergeordnete Klasse unserer Anwendung die Struktur und das gewünschte Verhalten der beiden anderen Klassen festlegen
Lassen Sie uns sehen, wie das geht
class BaseGame:
# Länge, um die die Nachricht zentriert ist
message_lenght = 60
description = ""
def __init__(self, points_to_win, n_lives=3):
"""Base game class
Args:
points_to_win (int): die Punkte, die das Spiel benötigt, um beendet zu werden
n_lives (int): Die Anzahl der Leben, die der Schüler hat. Der Standardwert ist 3.
"""
self.points_to_win = points_to_win
self.points = 0
self.lives = n_lives
def get_numeric_input(self, message=""):
while True:
# Holen Sie die Benutzereingabe
user_input = input(message)
# Wenn die Eingabe numerisch ist, geben Sie sie zurück
# Wenn nicht, geben Sie eine Meldung aus und wiederholen Sie
if user_input.isnumeric():
return int(user_input)
else:
print("Die Eingabe muss eine Zahl sein")
continue
def print_welcome_message(self):
print("PYTHON MULTIPLICATION GAME".center(self.message_lenght))
def print_lose_message(self):
print("SORRY YOU LOST ALL OF YOUR LIVES".center(self.message_lenght))
def print_win_message(self):
print(f "HERZLICHEN GLÜCKWUNSCH SIE HABEN {self.points}".center(self.message_lenght))
def print_current_lives(self):
print(f "Sie haben derzeit {self.leben} Leben\n")
def print_current_score(self):
print(f"\nIhr Punktestand ist {self.points}")
def print_description(self):
print("\n\n" self.description.center(self.message_lenght) "\n")
# Grundlegende Laufmethode
def run(self):
self.print_welcome_message()
self.print_description()
Wow, das scheint eine ziemlich große Klasse zu sein. Lassen Sie mich das genauer erklären
Zunächst einmal müssen wir die Klassenattribute und den Konstruktor verstehen
Grundsätzlich sind Klassenattribute Variablen, die innerhalb der Klasse, aber außerhalb des Konstruktors oder einer Methode erstellt werden
Während Instanzattribute Variablen sind, die nur innerhalb des Konstruktors erstellt werden
Der Hauptunterschied zwischen diesen beiden ist der Geltungsbereich, d.h. Klassenattribute sind sowohl von einem Instanzobjekt als auch von der Klasse aus zugänglich. Auf Instanzattribute hingegen kann nur von einem Instanzobjekt aus zugegriffen werden
game = BaseGame(5)
#
Zugriff auf game message lenght class attr from class
print(game.message_lenght) # 60
#
Zugriff auf die message_lenght class attr from class
print(BaseGame.message_lenght) # 60
#
Zugriff auf die points instance attr from instance
print(game.points) # 0
#
Zugriff auf das points instance attribute from class
print(BaseGame.points) # Attribute error
Ein weiterer Artikel kann dieses Thema vertiefen. Bleiben Sie in Kontakt, um ihn zu lesen
Die Funktionget_numeric_input
wird verwendet, um zu verhindern, dass der Benutzer Eingaben macht, die nicht numerisch sind. Wie Sie vielleicht bemerken, ist diese Methode so konzipiert, dass sie den Benutzer so lange fragt, bis sie eine numerische Eingabe erhält. Wir werden sie später in den Klassen des Kindes verwenden
Mit den print-Methoden können wir uns die Wiederholung des Ausdrucks bei jedem Ereignis im Spiel sparen
Zu guter Letzt ist die run-Methode nur ein Wrapper, der von den Klassen Zufallsmultiplikation und Tabellenmultiplikation verwendet wird, um mit dem Benutzer zu interagieren und alles funktionsfähig zu machen
Erstellen der Klassen des Kindes
Nachdem wir die übergeordnete Klasse erstellt haben, die die Struktur und einen Teil der Funktionalität unserer Anwendung festlegt, ist es an der Zeit, die eigentlichen Spielmodusklassen zu erstellen, indem wir die Macht der Vererbung nutzen
Klasse für Zufallsmultiplikation
Diese Klasse wird den “ersten Modus” unseres Spiels ausführen. Sie wird natürlich das Zufallsmodul verwenden, das uns die Möglichkeit gibt, dem Benutzer Zufallsoperationen von 1 bis 10 vorzuschlagen. Hier ist ein ausgezeichneter Artikel über das random (und andere wichtige Module) 😉
import random # Modul für Zufallsoperationen
class RandomMultiplication(BaseGame):
description = "In diesem Spiel müssen Sie die Zufallsmultiplikation richtig beantworten\Sie gewinnen, wenn Sie 5 Punkte erreichen, oder verlieren, wenn Sie alle Ihre Leben verlieren"
def __init__(self):
# Die zum Gewinnen benötigte Punktzahl ist 5
# Übergeben Sie 5 "points_to_win" Argument
super().__init__(5)
def get_random_numbers(self):
first_number = random.randint(1, 10)
second_number = random.randint(1, 10)
return first_number, second_number
def run(self):
# Ruft die obere Klasse auf, um die Willkommensnachrichten zu drucken
super().run()
while self.lives > 0 and self.points_to_win > self.points:
# Ermittelt zwei Zufallszahlen
number1, number2 = self.get_random_numbers()
operation = f"{number1} x {number2}: "
# Fordert den Benutzer auf, diese Operation zu beantworten
# Verhindert Wertefehler
user_answer = self.get_numeric_input(message=operation)
if user_answer == number1 * number2:
print("\nIhre Antwort ist richtig\n")
# Fügt einen Punkt hinzu
self.points = 1
else:
print("\nSorry, your answer is incorrect\n")
# Subtrahiert ein Leben
self.leben -= 1
self.print_current_score()
self.print_current_lives()
# Wird nur ausgeführt, wenn das Spiel beendet ist
# Und keine der Bedingungen erfüllt ist
else:
# Druckt die letzte Nachricht
if self.points >= self.points_to_win:
self.print_win_message()
else:
self.print_lose_message()
Hier ist eine weitere umfangreiche Klasse 😅. Aber wie ich schon sagte, es geht nicht um die Anzahl der Zeilen, sondern darum, wie lesbar und effizient sie ist. Und das Beste an Python ist, dass es Entwicklern erlaubt, sauberen und lesbaren Code zu erstellen, als ob sie normales Englisch sprechen würden
Diese Klasse hat eine Sache, die Sie vielleicht verwirrt, aber ich werde sie so einfach wie möglich erklären
# Elternklasse
def __init__(self, points_to_win, n_lives=3):
“
...
# Kindklasse
def __init__(self):
# Die Anzahl der Punkte, die zum Gewinnen benötigt werden, beträgt 5
# Übergeben Sie 5 "points_to_win" Argumente
super().__init__(5)
Der Konstruktor der Kindklasse ruft die Superfunktion auf, die sich gleichzeitig auf die Elternklasse (BaseGame) bezieht. Damit wird Python im Grunde gesagt
Fülle
das Attribut “points_to_win” der Elternklasse mit 5!
Es ist nicht notwendig, self in den super().__init__()
-Teil einzufügen, nur weil wir super innerhalb des Konstruktors aufrufen, und das würde zu einer Überschneidung führen
Wir verwenden die super-Funktion auch in der run-Methode und wir werden sehen, was in diesem Teil des Codes passiert
#
Grundlegende run-Methode
# Übergeordnete Methode
def run(self):
self.print_welcome_message()
self.print_description()
def run(self):
# Aufruf der oberen Klasse, um die Willkommensnachrichten zu drucken
super().run()
....
Wie Sie vielleicht bemerken, druckt die run-Methode in der übergeordneten Klasse die Begrüßungs- und Beschreibungsnachricht aus. Es ist jedoch eine gute Idee, diese Funktionalität beizubehalten und auch in den untergeordneten Klassen zusätzliche Funktionen hinzuzufügen. Dementsprechend verwenden wir super , um den gesamten Code der übergeordneten Methode auszuführen, bevor wir den nächsten Teil ausführen
Der andere Teil der Ausführungsfunktion ist ziemlich einfach. Sie fragt den Benutzer nach einer Zahl mit der Nachricht der Operation, die er beantworten muss. Dann wird das Ergebnis mit der realen Multiplikation verglichen und wenn sie gleich sind, wird ein Punkt hinzugefügt, wenn sie nicht gleich sind, wird 1 Leben abgezogen
Es ist erwähnenswert, dass wir while-else-Schleifen verwenden. Das würde den Rahmen dieses Artikels sprengen, aber ich werde in ein paar Tagen einen Artikel darüber veröffentlichen
Schließlich verwendet get_random_numbers die Funktion random.randint, die eine zufällige ganze Zahl innerhalb des angegebenen Bereichs zurückgibt. Dann gibt sie ein Tupel aus zwei zufälligen Ganzzahlen zurück
Klasse für zufällige Multiplikation
Der “zweite Modus” muss das Spiel in Form einer Multiplikationstabelle anzeigen und sicherstellen, dass der Benutzer mindestens 2 Tabellen richtig beantwortet
Zu diesem Zweck nutzen wir wieder die Macht von super und ändern das Attribut points_to_win der Elternklasse auf 2
class TableMultiplication(BaseGame):
description = "In diesem Spiel müssen Sie die komplette Multiplikationstabelle richtig auflösen. Sie gewinnen, wenn Sie 2 Tabellen lösen"
def __init__(self):
# Muss 2 Tabellen vervollständigen, um zu gewinnen
super().__init__(2)
def run(self):
# Druckt Willkommensnachrichten
super().run()
while self.lives > 0 and self.points_to_win > self.points:
# Ermittelt zwei Zufallszahlen
number = random.randint(1, 10)
for i in range(1, 11):
if self.lives <= 0:
# Sicherstellen, dass das Spiel nicht fortgesetzt werden kann
# wenn der Benutzer die Leben verbraucht
self.points = 0
break
operation = f"{number} x {i}: "
user_answer = self.get_numeric_input(message=operation)
if user_answer == Zahl * i:
print("Toll! Ihre Antwort ist richtig")
else:
print("Leider ist Ihre Antwort nicht richtig")
self.lives -= 1
self.punkte = 1
# Wird nur ausgeführt, wenn das Spiel beendet ist
# Und keine der Bedingungen erfüllt ist
else:
# Druckt die letzte Nachricht
if self.points >= self.points_to_win:
self.print_win_message()
else:
self.print_lose_message()
Wie Sie sehen können, ändern wir nur die Run-Methode dieser Klasse. Das ist die Magie der Vererbung, wir schreiben einmal die Logik, die wir an mehreren Stellen verwenden, und vergessen sie 😅
In der Run-Methode verwenden wir eine for-Schleife, um die Zahlen von 1 bis 10 zu erhalten und die Operation zu erstellen, die dem Benutzer angezeigt wird
Wenn die Leben aufgebraucht sind oder die zum Gewinnen benötigten Punkte erreicht sind, bricht die while-Schleife ab und die Nachricht über Sieg oder Niederlage wird angezeigt
YEAH, wir haben die beiden Modi des Spiels erstellt, aber bis jetzt passiert nichts, wenn wir das Programm ausführen
Lassen Sie uns also das Programm abschließen, indem wir die Wahl des Modus implementieren und die Klassen instanziieren, die von dieser Wahl abhängen
Implementierung der Auswahl
Der Benutzer kann wählen, welchen Modus er spielen möchte. Schauen wir uns also an, wie man das implementiert
if __name__ == "__main__":
print("Spielmodus auswählen")
choice = input("[1],[2]: ")
if choice == "1":
game = RandomMultiplication()
elif choice == "2":
game = TableMultiplication()
else:
print("Bitte wählen Sie einen gültigen Spielmodus aus")
exit()
game.run()
Zunächst bitten wir den Benutzer, zwischen den Modi 1 oder 2 zu wählen. Wenn die Eingabe ungültig ist, wird das Skript nicht weiter ausgeführt. Wenn der Benutzer den ersten Modus auswählt, führt das Programm den Spielmodus Zufallsmultiplikation aus, und wenn er den zweiten auswählt, wird der Modus Tabellenmultiplikation ausgeführt
So würde es aussehen
Fazit
Herzlichen Glückwunsch, Sie haben gerade eine Python-Anwendung mit objektorientierter Programmierung erstellt
Der gesamte Code ist im Github-Repository verfügbar
In diesem Artikel haben Sie gelernt,
- Python-Klassenkonstruktoren verwenden
- Eine funktionale Anwendung mit OOP erstellen
- Die Superfunktion in Python-Klassen zu verwenden
- Die grundlegenden Konzepte der Vererbung anzuwenden
- Klassen- und Instanzattribute zu implementieren
Viel Spaß beim Programmieren 👨💻
Als Nächstes lernen Sie einige der besten Python-IDEs für mehr Produktivität kennen.