Mastodon
Aufgabe und Lernziele
Ziel dieser Aufgabe ist es, eine Python-Anwendung zu erstellen, die die Mastodon-API nutzt, um Toots (so heißen die Beiträge, die man bei Mastodon veröffentlicht) abzurufen und anhand bestimmter Kriterien zu filtern. Dazu werden Sie Toot-Objekte verwenden, die wichtige Informationen wie Inhalt, Hashtags und Medien speichern. Anschließend erstellen Sie Trigger-Klassen, um Toots auf Eigenschaften wie Hashtags oder Medien zu prüfen und so eine flexible Filterung zu ermöglichen.
Ihre Implementierung soll das von uns vorgegebene Aufgabenmaterial nutzen. Der erste Schritt besteht darin, das Aufgabenmaterial herunterzuladen und sich Zugang zur Mastodon-API zu verschaffen. Folgen Sie dazu den folgenden Schritten.
Wozu das alles? Mit dieser Aufgabe üben Sie zum einen den Umgang mit den objektorientierten Konzepten von Python. Zum anderen lernen Sie, sich im Ökosystem von Python zurechtzufinden und mit einer kleinen Auswahl der verfügbaren Werkzeuge zu arbeiten. Die Aufgabenstellung erläutert die meisten Schritte sehr kleinteilig. An einigen Stellen sind die Hinweise weniger genau, um Ihnen Spielraum zu geben, die Lösung selbst zu erkunden.
Keine Sorge, wenn Ihnen diese Aufgabe auf den ersten Blick komplex erscheint! Wir haben sie in kleine, überschaubare Schritte unterteilt und führen Sie Schritt für Schritt durch die Implementierung. Am Ende werden Sie erstaunt sein, was für eine leistungsfähige Anwendung Sie selbst entwickelt haben. Nehmen Sie sich die Zeit, die Sie brauchen – Programmieren lernt man, indem man nicht weiter weiß und Hindernisse überwindet.
Wir erwarten nicht, dass Sie diese Aufgabe aus dem Stand und ohne Hilfe komplett eigenständig lösen können. Helfen Sie sich gegenseitig! Nutzen Sie das Forum und die Tutorien!
Vorbereitung
Material herunterladen
Öffnen Sie VS Code entsprechend Ihrem Setup, klicken Sie auf Ihr Terminalfenster und führen Sie cd
aus. Die Eingabeaufforderung Ihres Terminalfensters sollte ungefähr wie folgt aussehen:
$
Laden Sie das Aufgabenmaterial herunter:
wget https://inf.zone/download/exercises/07/mastodon_oop.zip
Sie müssen das Material noch entpacken. Das kann mit folgendem Befehl gemacht werden:
unzip mastodon_oop.zip
Anschließend können Sie die zip-Datei entfernen:
rm mastodon_oop.zip
Nun können Sie mit
cd mastodon_oop
in das Verzeichnis der Aufgabe navigieren.
Wenn Sie ls
ausführen, sollten Sie nun folgende Datei gelistet sehen:
mastodon_oop.py
Für diese Aufgabe müssen Sie zusätzlich ein Python-Paket installieren. Das können Sie mit folgenden Befehl machen:
pip install Mastodon.py
Was macht dieser Befehl
Folgen Sie den oben genannten Schritten erneut, falls Sie auf Probleme stoßen sollten.
Wie immer, wenn Sie ein bestehendes Codegerüst erhalten, sollten Sie sich zuerst damit vertraut machen. Sehen Sie sich also die Datei mastodon_oop.py
genauer an.
- Sehen Sie sich alle gegebenen Funktionen und Klassen an.
- Lesen Sie alle
TODO
-Kommentare durch. - Was bedeutet
pass
in den noch nicht implementierten Funktionen und Klassen? (siehe The pass statement)
API-Zugriff
Ein API-Zugriff bezieht sich auf die Möglichkeit, mit einer Programmierschnittstelle (API) zu interagieren und diese zu nutzen. Eine API ist eine Sammlung von Regeln und Protokollen, die es verschiedenen Softwareanwendungen ermöglicht, miteinander zu kommunizieren und zu interagieren. Sie definiert die Methoden und Datenformate, die Anwendungen verwenden können, um Informationen anzufordern und auszutauschen.
APIs ermöglichen es Entwicklern, auf die Funktionalitäten einer bestimmten Software, eines Dienstes oder einer Plattform zuzugreifen, z.B. um Daten abzurufen, Operationen auszuführen oder Integrationen mit anderen Systemen vorzunehmen. So stellen beispielsweise soziale Netzwerke wie Facebook, Twitter oder Mastodon APIs zur Verfügung, mit denen Entwickler Benutzerdaten abrufen, Updates posten oder Beiträge abrufen können.
Der Zugriff auf APIs erfolgt in der Regel über eine Kombination aus einem API-Schlüssel oder Token und spezifischen Endpunkten (URLs). Der API-Schlüssel dient als eindeutiger Identifikator, der die Berechtigung für den API-Zugriff erteilt. Endpunkte sind die URLs, die die verschiedenen Aktionen oder Operationen spezifizieren, die über die API verfügbar sind. APIs sind entscheidend für die Integration verschiedener Dienste und Systeme. Sie ermöglichen es Entwicklern, leistungsfähigere und komplexere Anwendungen zu erstellen, indem sie die Funktionalitäten und Daten anderer Dienste nutzen.
Wir nutzen im Folgenden das Mastodon.py Python-Paket. Dies ist ein Wrapper (Abstraktionsschicht, die die Funktionalität eines bestehenden Systems oder Moduls kapselt), der die Kommunikation mit der API abstrahiert und vereinfacht.
Mastodon API
Mastodon ist eine Social-Media-Plattform und Teil der Bewegung für dezentralisierte soziale Netzwerke.
Sie wurde von Eugen Rochko entwickelt und im Jahr 2016 als Alternative zu traditionellen, zentralisierten Social-Media-Plattformen ins Leben gerufen. Mastodon ist eine Open-Source-Software, was bedeutet, dass der Quellcode frei verfügbar ist und von jedem genutzt, verändert und weiterverbreitet werden kann.
Im Gegensatz zu herkömmlichen sozialen Netzwerken arbeitet Mastodon nach einem föderierten Modell. Statt eines zentralen Servers, der alle Benutzerkonten und Inhalte hostet, besteht Mastodon aus unabhängig betriebenen Servern, sogenannten „Instanzen“, die miteinander ein größeres Netzwerk bilden. Jede Instanz ist eine eigenständige Community mit eigenen Regeln und Moderationsrichtlinien, und die Nutzer können sich basierend auf ihren Interessen oder Vorlieben für eine Instanz entscheiden.
Auf Mastodon können Nutzer Nachrichten veröffentlichen, die Toots genannt werden und Text, Bilder, Videos oder Links enthalten können. Sie können anderen Nutzern folgen, entweder aus ihrer eigenen Instanz oder aus anderen Instanzen. Interaktionen zwischen den Instanzen innerhalb des Mastodon-Netzwerks sind problemlos möglich.
Zugriff auf die Mastodon-API erhalten
- Erstellen Sie ein Mastodon-Konto auf dem Server Mastodon.social.
- Generieren Sie einen Zugriffstoken, der es Ihrem Code ermöglicht, im Rahmen dieser API-Schnittstelle in Ihrem Namen zu agieren.
- Melden Sie sich in Ihrem Konto an.
- Navigieren Sie zu
Preferences
, indem Sie auf die drei Punkte rechts neben Ihrem Benutzernamen und dann aufPreferences
klicken. - Es öffnen sich die Einstellungen. Klicken Sie dort auf
Development
in der Navigationsleiste am linken Seitenrand. - Nun können Sie hier einen neuen Zugriffstoken erstellen. Wählen Sie
New application
oben rechts. - Sie sehen nun ein Fenster, in dem Sie den Namen Ihrer Applikation (
Application name
) angeben können. Wählen Sie einen passenden Namen für Ihre Applikation. - Unter
Scopes
wählen Sieread
. Lassen Sie den Rest unverändert. - Scrollen Sie nach unten, um den Zugriffstoken mit einem Klick auf
Submit
zu erstellen.
- Speichern Sie die wichtigen Zugangsdaten:
- Nachdem Sie Ihren Zugriffstoken nun erstellt haben, finden Sie ihn in der Liste, zu der Sie automatisch nach dem Abschließen des vorherigen Schritts weitergeleitet werden.
- Klicken Sie auf den
Application Name
Ihres Zugriffstokens (DenApplication Name
sehen Sie in der ersten Spalte der Tabelle). - Es öffnet sich eine Ansicht, in der Sie den
Client key
, dasClient secret
undAccess Token
finden. Speicher Sie diese drei Parameter.
- Authentifizieren Sie Ihre Anwendung im Code:
- Kehren Sie zu VS Code zurück und öffnen Sie die Datei
mastodon_oop.py
sofern Sie das nicht bereits gemacht haben. - Geben Sie an den vorgesehen Stellen Ihren
Client key
, IhrClient secret
und IhrenAccess Token
an entsprechenden Stellen in der vorgegebenen Datei ein. api_base_url
müssen Sie nicht ändern.
- Kehren Sie zu VS Code zurück und öffnen Sie die Datei
Objektorientierte Modellierung
Toot-Objekt
Ein Toot in Mastodon ist vergleichbar mit einem Tweet auf Twitter. In dieser Aufgabenstellung filtern Sie Toots, auf die Sie mithilfe der API Zugriff erhalten haben. Ziel ist es, Informationen über ein Toot-Objekt zu speichern, die dann im weiteren Verlauf des Programms verwendet werden können. Heruntergeladene Toots sind in der Regel Wörterbücher, die verschiedene Informationen zum jeweiligen Toot enthalten.
Ihre Aufgabe in dieser Teilaufgabe ist es, eine Klasse Toot
zu schreiben. Beginnen Sie mit einem Initialisierer (__init__
), der die folgenden Parameter entgegennimmt:
content
: Der Inhalt des Tootsaccount
: Informationen zum Konto, das den Toot erstellt hathashtags
: Eine Liste der verwendeten Hashtagspubdate
: Das Veröffentlichungsdatummedia
: Medieninhalte, die im Toot enthalten sind
Speichern Sie diese Parameter als private Instanzvariablen. Wenn Sie zukünftig auf die Variablen zugreifen wollen, so können Sie das Property-Decorator-Konzept verwenden. Nutzen Sie dafür den Dekorator @property
, um den Zugriff auf die Instanzvariablen zu ermöglichen. Der Zugriff auf die Variablen aus anderen Klassen, die wir später implementieren werden, erfolgt dadurch bequem über toot.content
, toot.account
usw.
Fügen Sie außerdem eine __str__
-Methode zur Klasse Toot hinzu, um eine lesbare Darstellung eines Toots zu ermöglichen. Diese Methode sollte einen informativen String zurückgeben, der die wichtigsten Attribute des Toots enthält. Dies erleichtert die Anzeige von Toot
-Objekten im weiteren Verlauf des Programms.
Orientieren Sie sich bei Ihrer Implementierung an der bereitgestellten Vorlage (mastodon_oop.py
).
Text aus HTML isolieren
Der content
eines Toots enthält HTML, das für die Darstellung im Web optimiert ist. Wenn jedoch nur der reine Text aus diesem HTML benötigt wird – etwa zur Analyse oder Weiterverarbeitung –, muss der HTML-Code entfernt werden.
Ihre Aufgabe ist es nun, eine Funktion namens get_text_content
zu implementieren, die ein Toot (als dict
) als Eingabe erhält.
Das dict
enthält einen Schlüssel namens content
, der einen HTML-String enthält.
Entwickeln Sie ein Programm, das den Textinhalt aus dem HTML extrahiert und zurückgibt. Nutzen Sie dafür die Bibliothek Beautiful Soup.
Tipps
- Die Beautiful Soup-Bibliothek bietet eine Methode namens
get_text
. Diese wird auf ein Objekt angewandt und gibt den Textinhalt eines HTML-Baums zurück. - Um diese Methode zu nutzen, muss ein Beautiful Soup-Objekt erstellt werden. Dafür initialisieren Sie ein solches Objekt mit dem Toot (HTML-Inhalt) und dem Attribut
html.parser
. Werfen Sie hier einen Blick in die Beautiful Soup Dokumentation.
Toots von Mastodon abfragen
Nun sollen Sie Toots von Mastodon abfragen und hierbei die bereits implementierten Konstrukte entsprechend nutzen.
Die Dokumentation zu Mastodon.py enthält eine Funktion namens timeline_hashtag
, die einen Hashtag als Eingabe erhält und ein dict
mit verschiedenen Informationen zu allen Toots zurückgibt, die diesen Hashtag enthalten.
Schauen Sie sich zuerst an, wie ein Toot Status dict aufgebaut ist. Sie werden feststellen, dass im Status dict von Mastodon andere Schlüssel verwendet werden als wir in unserem Toot-Objekt verwenden:
hashtags
hat den Schlüsseltags
pubdate
hat den Schlüsselcreated_at
media
hat den Schlüsselmedia_attachments
Die Informationen eines Toots sollen in dem zuvor implementierten Toot-Objekt gespeichert werden. Begrenzen Sie die Funktion auf maximal 10 Toots, die geladen werden.
Ihre Aufgabe ist es, eine Funktion namens load
zu schreiben, die einen Hashtag als Eingabe entgegennimmt, Gehen Sie dabei wie folgt vor:
- Initialisieren Sie eine leere Liste, in der Sie die Toots während des Prozesses speichern.
- Rufen Sie die Mastodon-API auf, um alle Toots zu erhalten, die den angegebenen Hashtag erhalten (denken Sie daran, dies auf 10 Toots zu begrenzen). Hier ist es sinnvoll einen Blick in die Dokumentation zu werfen. Mithilfe von
limit=10
können Sie direkt10
als Argument für den Parameterlimit
übergeben. - Verwenden Sie die heruntergeladenen Toots, um Instanzen des
Toot
-Objekts zu erstellen und fügen Sie diese der Toot-Liste hinzu. - Am Ende gibt die Funktion die gefüllte Toot-Liste zurück, die aus 10
Toot
-Objekten besteht.
Haben Sie Probleme, die von Mastodon heruntergeladenen Daten zu verarbeiten?
toot_data = mastodon.timeline_hashtag(hashtag, limit=10)
gibt eine Liste an Toots in der Form eines dict
s zurück.
Somit können Sie mithilfe einer for
-Schleife über die Liste iterieren:
for data in toot_data:
# TODO: create toot-objects from data
Dadurch erhalten Sie die Daten zu jedem Toot, woraus Sie nun Toot-Objekte erstellen können. Nutzen Sie dafür den Code, den Sie in der Sektion Text aus HTML isolieren geschrieben haben.
Lassen Sie sich data
doch einmal auf der Konsole ausgeben, um sich die Struktur klar zu machen.
Tipps
- Der Toot-Inhalt sollte als String und nicht als HTML-Skript gespeichert werden. Nutzen Sie dafür die Funktion
get_text_content
.
Filtermechanismen – Trigger
Trigger sind Regeln, die bestimmen, ob ein Beitrag die festgelegten Kriterien erfüllt. Sie können sich auf den Inhalt der Beiträge beziehen, z.B. auf bestimmte Phrasen, Medientypen oder der Zeitpunkt, zu dem die Beiträge veröffentlicht wurden. Trigger können einzeln verwendet oder mithilfe von zusammengefassten Triggern kombiniert werden, um komplexere Filterregeln zu erstellen.
Ihre Aufgabe ist es, Trigger zu erstellen, die auf die in der load
-Funktion geladenen Toots angewendet werden.
Nachdem Sie alle Trigger-Klassen erstellt haben, schreiben Sie eine Funktion, die eine Stichprobe von Triggern und Toots durchgeht und überprüft, ob ein bestimmter Beitrag alle angegebenen Trigger-Kriterien erfüllt.
In den folgenden Teilaufgaben werden Sie Stück für Stück ans Ziel geleitet.
Trigger Superklasse
Hierbei handelt es sich um die Trigger
-Klasse. Im gegeben Code ist diese Klasse bereits fertig implementiert. Sie müssen daran nichts mehr ändern.
Es handelt sich dabei um eine Klasse, die als Superklasse für alle Trigger dient. Sie enthält die Methode evaluate
, die verwendet wird, um zu beurteilen, ob ein Filter für einen bestimmten Beitrag in Mastodon erfüllt ist. Beachten Sie, dass die evaluate
-Methode ein Toot-Objekt übergeben bekommt. Alle Trigger
-Klassen sollen von dieser Klasse erben.
Eine Unterklasse verwendet die Methoden der Superklasse, wenn sie diese nicht selbst überschreibt. Wenn Sie die Methode evaluate
in einer Unterklasse nicht überschreiben, wird die Methode der Superklasse (Trigger
) aufgerufen. Diese löst jedoch einen Fehler (NotImplementedError
) aus, weil sie nicht implementiert ist.
Media-Trigger
In dieser Teilaufgabe werden wir die Trigger
-Klasse verwenden. Sie sollen hier die MediaTrigger
-Klasse implementieren. Diese ist eine spezielle Art von Trigger
, der ausgelöst wird, wenn ein Toot Medienanhänge wie Bilder, Videos, GIFs oder Audiodateien enthält.
Um diesen Trigger
zu implementieren, greifen Sie auf das media
-Attribut des Toot-Objekts zu, das die Medienanhänge speichert. Überprüfen Sie, ob dieses media
-Attribut nicht leer ist. Falls es Medienanhänge enthält, geben Sie True
zurück. Wenn keine Medien vorhanden sind, geben Sie False
zurück. Denken Sie daran, dass diese Klasse von der Trigger
-Klasse erbt.
Sie sind sich unsicher, ob Sie diese Klasse richtig implementiert haben?
Folgende Fragen, können Ihnen bei der Implementierung helfen:
- Haben Sie die
MediaTrigger
-Klasse so implementiert, dass sie von derTrigger
-Klasse erbt? - Hat Ihre
MediaTrigger
-Klasse eineevaluate
-Methode? - Prüfen Sie in der
evaluate
-Methode, ob ein Toot-Objekt Medienanhänge hat? Das heißt, prüfen Sie, obmedia
eine leere Liste ist und geben dementsprechendTrue
oderFalse
zurück?
Können Sie alle Fragen mit “Ja” beantworten?
Sollten diese Fragen nicht weiter helfen, können Sie sich selbstverständlich die unten stehenden Tipps anschauen.
Tipps
- Die
MediaTrigger
-Klasse sollte von derTrigger
-Klasse erben.class MediaTrigger(Trigger): ...
- Sie sollte eine
evaluate
-Methode beinhalten.def evaluate(self, toot): ...
- Es muss sichergestellt werden, ob ein Toot-Objekt überhaupt Medienanhänge enthält. Dementsprechend muss geprüft werden, ob
media
eine leere Liste ist. Ist dies der Fall, so beinhaltet das entsprechende Toot-Objekt keine Medienanhänge. Es soll alsoFalse
zurückgegeben werden – andernfallsTrue
:def evaluate(self, toot): return bool(toot.media)
Image-Trigger
Nun wollen wir in einer weiteren Klasse von der MediaTrigger
-Klasse erben. Dafür sollen Sie die ImageMediaTrigger
-Klasse implementieren.
Der ImageMediaTrigger
wird ausgelöst, wenn ein Beitrag ein oder mehrere Bildanhänge enthält. Das heißt es muss ein nicht leeres media
-Attribut geben und zusätzlich muss dieses ein Bild sein. Somit sollte Ihre Klasse von MediaTrigger
erben.
Um diesen MediaTrigger
zu implementieren, greifen Sie auf das media
-Attribut des Toot-Objekts zu, das die Medienanhänge speichert. Überprüfen Sie, ob das media
-Attribut nicht leer ist und mindestens einen Bildanhang enthält.
Was steckt nun hinter dem media
-Attribut? Wie können Sie auf den Typ eines Medienanhangs zugreifen, um zu prüfen, ob es ein Bildanhang ist? Lassen Sie sich hierfür das media
-Attribut einmal auf der Konsole ausgeben.
Wenn mindestens ein Bildanhang enthalten ist, geben Sie True
zurück, was anzeigt, dass der Trigger auslöst. Andernfalls geben Sie False
zurück. Wenn es sich um einen Bildanhang handelt, so ist type == 'image'
. Beachten Sie, dass diese Klasse von der MediaTrigger
-Klasse erbt.
Sie sind sich unsicher, ob Sie diese Klasse richtig implementiert haben?
Folgende Fragen, können Ihnen bei der Implementierung helfen:
- Haben Sie die
ImageMediaTrigger
-Klasse so implementiert, dass sie von derMediaTrigger
-Klasse erbt? - Hat Ihre
ImageMediaTrigger
-Klasse eineevaluate
-Methode? - Ist Ihnen klar, dass Sie mittels
media[type]
auf dentype
eines Medienanhangs zugreifen können? - Stellen Sie sicher, dass Sie beim Aufruf von
evaluate
auch prüfen, ob das Toot-Objekt Medienanhänge enthält?
Sollten diese Fragen nicht weiter helfen, können Sie sich selbstverständlich die unten stehenden Tipps anschauen.
Tipps
- Die
ImageMediaTrigger
-Klasse sollte von derMediaTrigger
-Klasse erben.class ImageMediaTrigger(MediaTrigger): ...
- Sie sollte eine
evaluate
-Methode beinhalten.def evaluate(self, toot): ...
- Es muss sichergestellt werden, ob ein Toot-Objekt überhaupt Medienanhänge beinhaltet. Dabei können wir es uns zu nutze machen, dass diese Klasse von der
MediaTrigger
-Klasse erbt. Dementsprechend könnte dieevaluate
-Methode wie folgt aussehen:def evaluate(self, toot): if not super().evaluate(toot): return False return any(media['type'] == 'image' for media in toot.media)
- Mit
return any(media['type'] == 'image' for media in toot.media)
kann man nun prüfen, ob ein Medienanhang in der Listetoot.media
ein Bildanhang (image
) ist.
Video-Trigger
Die VideoMediaTrigger
-Klasse ist sehr ähnlich zur ImageMediaTrigger
-Klasse, die Sie soeben implementiert haben.
Der VideoMediaTrigger
wird ausgelöst, wenn ein Beitrag ein oder mehrere Videoanhänge enthält.
Um diesen MediaTrigger
zu implementieren, greifen Sie auf das media
-Attribut des Beitragobjekts zu, das die Medienanhänge speichert. Überprüfen Sie, ob das media
-Attribut nicht leer ist und mindestens einen Videoanhang enthält.
Wenn dies der Fall ist, geben Sie True
zurück, andernfalls geben Sie False
zurück. Wenn es sich um einen Videoanhang handelt, so ist type == 'video'
. Beachten Sie, dass diese Klasse von der MediaTrigger
-Klasse erbt.
Trigger
-Klassen mehr, sondern widmen uns noch einigen anderen Triggern.
Phrase-Trigger
Um nach konkreten Phrasen (Sätzen/Wörtern) im Textinhalt eines Toots suchen zu können, sollen Sie nun eine PhraseTrigger
-Klasse implementieren.
Der PhraseTrigger
ist ein Trigger
, der ausgelöst wird, wenn ein Toot eine bestimmte Phrase in seinem Textinhalt enthält.
Um diesen Trigger
zu implementieren, übergeben Sie beim Erstellen einer Instanz von PhraseTrigger
die gewünschte Phrase als Argument und speichern Sie sie als Attribut des Triggers.
Das heißt, im Gegensatz zu den Triggern, die Sie bis jetzt implementiert haben, benötigt dieser Trigger eine konkrete __init__
-Methode, die ein Argument entgegen nehmen kann.
In der evaluate
-Methode greifen Sie auf das content
-Attribut des Toot-Objekts zu, um den Textinhalt des Toots zu erhalten.
Konvertieren Sie sowohl den Textinhalt als auch die Phrase in Kleinbuchstaben, um den Vergleich unabhängig von der Groß-/Kleinschreibung durchzuführen.
Entfernen Sie dann alle Satzzeichen (.
, ,
, !
, ?
) aus dem Textinhalt, indem Sie sie durch leere Zeichen ersetzen. Überprüfen Sie abschließend, ob die Phrase im Textinhalt enthalten ist.
Wenn dies der Fall ist, geben Sie True
zurück, andernfalls False
. Beachten Sie, dass diese Klasse von der Trigger
-Klasse erbt.
Time Trigger
Das Toot-Objekt enthält auch ein pubdate
-Attribut. Wir können dieses nutzen, um nach dem Veröffentlichungsdatum von Toots zu filtern. Hierzu erstellen Sie im Folgenden eine TimeTrigger
-Klasse.
Der TimeTrigger
ist ein Trigger
, der ausgelöst wird, basierend auf der Veröffentlichungszeit eines Toots.
Erstellen Sie eine Klasse TimeTrigger
. Die Klasse soll einen Initialisierer enthalten, der zwei Parameter akzeptiert. Der erste ist ptime
, einen String im Format "YYYY-MM-DD HH:MM:SS"
, der die gewünschte Zeit beschreibt.
Der zweite Parameter ist timezone
. Ändern Sie diesen Parameter so ab, dass er eine optionale Angabe für die Zeitzone ist, die Sie standardmäßig auf EST
setzen sollen. Wenn Ihnen unklar ist, wie Sie das machen sollen, dann können Sie dazu das unten stehende Hilfefenster (Hilfe zu Standardparametern) öffnen.
Der übergebene ptime
-String soll in ein datetime
-Objekt umgewandelt werden. Anschließend soll mithilfe der Bibliothek pytz
die angegebene Zeitzone hinzugefügt werden, sodass ptime
korrekt lokalisiert ist.
Da TimeTrigger
eine abstrakte Klasse ist, ist keine Implementierung einer evaluate
-Methode erforderlich.
astimezone
, da sie den String nicht wie erforderlich formatiert.
Hilfe zu Standardparametern
Einen Standardparameter können Sie wie folgt implementieren:
def my_function(parameter="bar")
print(f"foo, {parameter}")
In diesem Beispiel sehen Sie eine Funktion my_function
. Diese kann einen Parameter parameter
erhalten und gibt diesen entsprechend auf der Konsole aus.
my_function
kann nun wie folgt aufgerufen werden:
my_function("my value")
Dabei erhalten Sie folgende Ausgabe auf der Konsole: foo, my value
.
Dies unterscheidet sich von der Situation, wenn Sie my_function
wie folgt aufrufen:
my_function()
Hier erhalten Sie folgende Ausgabe auf der Konsole: foo, bar
.
Es wird also der standardmäßige Wert bar
für parameter
genutzt.
Before-Trigger
Nun wollen wir die Unterklasse BeforeTrigger
-Klasse der TimeTrigger
-Klasse erstellen.
Der BeforeTrigger
ist ein TimeTrigger
, der ausgelöst wird, wenn ein Toot strikt vor der Auslösezeit veröffentlicht wurde. Die Auslösezeit (ptime
) haben Sie bereits in der Superklasse spezifiziert.
Um diesen Trigger
zu implementieren, müssen Sie den BeforeTrigger
als Unterklasse von TimeTrigger
erstellen.
Da der BeforeTrigger
von TimeTrigger
erbt, übernimmt er automatisch die __init__
-Methode der Superklasse, was bedeutet, dass Sie diese Methode nicht erneut definieren müssen.
In der evaluate
-Methode greifen Sie auf das pubdate
-Attribut des Toot-Objekts zu, um die Veröffentlichungszeit des Toots zu erhalten.
Falls der Toot vor der Auslösezeit veröffentlicht wurde, geben Sie True
zurück, andernfalls False
.
After-Trigger
Der AfterTrigger
ist ein TimeTrigger
, der ausgelöst wird, wenn ein Toot strikt nach der Auslösezeit veröffentlicht wurde.
Um diesen Trigger
zu implementieren, erstellen Sie die AfterTrigger
-Klasse als Unterklasse der TimeTrigger
-Klasse. Da der AfterTrigger
dem BeforeTrigger
sehr ähnlich ist, sollten Sie ähnliche Überlegungen wie bei der Implementierung des BeforeTrigger
anstellen. In der evaluate
-Methode greifen Sie auf das pubdate
-Attribut des Toot-Objekts zu, um die Veröffentlichungszeit des Toots zu erhalten. Falls der Toot nach der Auslösezeit veröffentlicht wurde, geben Sie True
zurück, andernfalls False
.
Trigger-Kombinationen
Im Folgenden wollen wir einige Klassen implementieren, um unsere bereits implementierten Trigger
-Klassen kombinieren zu können. Implementieren Sie hierfür die drei folgenden Klassen.
Not-Trigger
Der NotTrigger
ist ein Trigger
, der die Ausgabe eines anderen Triggers umkehrt.
Zur Implementierung wird beim Erstellen einer Instanz von NotTrigger
ein anderer Trigger
als Argument übergeben. Implementieren Sie die evaluate
-Methode so, dass dieser übergebene Trigger für den jeweiligen Toot ausgewertet wird. Anschließend soll das Ergebnis umgekehrt werden: Wenn der ursprüngliche Trigger True
zurückgibt, liefert der NotTrigger
also False
zurück, und umgekehrt.
And-Trigger
Der AndTrigger
ist ein Trigger
, der für einen Toot nur dann ausgelöst wird, wenn beide übergebenen Trigger für diesen Toot auslösen.
Beim Erstellen einer Instanz von AndTrigger
sollen zwei Trigger
als Argument übergeben werden. Implementieren Sie die evaluate
-Methode so, dass diese beiden Trigger für den jeweiligen Toot ausgewertet werden. Der AndTrigger
gibt nur dann True
zurück, wenn beide Trigger unabhängig voneinander ebenfalls True
zurückgeben. In allen anderen Fällen wird False
zurückgegeben.
Or-Trigger
Der OrTrigger
ist ein Trigger
, der für einen Toot ausgelöst wird, wenn mindestens einer (oder beide) der übergebenen Trigger für diesen Toot auslöst.
Beim Erstellen einer Instanz von OrTrigger
sollen zwei Trigger
als Argument übergeben werden. Implementieren Sie die evaluate
-Methode so, dass geprüft wird, ob einer der beiden Trigger für den jeweiligen Toot True
zurückgibt. Falls dies bei einem oder beiden Triggern der Fall ist, gibt der OrTrigger
ebenfalls True
zurück. Andernfalls wird False
zurückgegeben.
Zwischenfazit
Gratulation! Sie haben nun alle wichtigen Bausteine für Ihre Mastodon-Filteranwendung implementiert. Das war ein ganzes Stück Arbeit, aber Sie haben dabei zentrale Konzepte der objektorientierten Programmierung wie Vererbung, abstrakte Klassen und Polymorphie nicht nur theoretisch kennengelernt, sondern auch praktisch angewendet. Lassen Sie uns nun alles zusammenfügen und Ihre Implementierung in Aktion sehen!
Anwendung
Im Folgenden wollen wir die zuvor implementierten Klassen nutzen. Dafür müssen wir noch eine Funktion implementieren und dann alles zusammenfügen.
Filtern der Toots
Nun soll die Funktion filter_toots
implementiert werden. Sie dient dazu, Toots basierend auf den definierten Triggern zu filtern. Dafür wendet sie die implementierten Trigger auf die geladenen Toots an und gibt nur diejenigen zurück, die alle Filterkriterien erfüllen.
Erstellen Sie eine Funktion, die zwei Eingaben erwartet: eine Liste von Toots und eine Liste von Triggern, die Sie als trigger_list
bezeichnen. Gehen Sie wie folgt vor: Durchlaufen Sie jeden Toot in der Toot-Liste und überprüfen Sie für jeden Toot, ob alle Trigger aus der trigger_list
zutreffen. Wenden Sie dazu die evaluate
-Methode jedes Triggers auf den jeweiligen Toot an. Falls alle Trigger True
zurückgeben, soll der Toot in die Ergebnisliste aufgenommen werden.
Verwenden Sie dabei List-Comprehension, um die Liste der gefilterten Toots direkt zu erstellen. Am Ende gibt die Funktion diese Liste zurück, die nur die Toots enthält, die alle Bedingungen erfüllen.
Toots filtern und ausgeben
Nachdem Sie alle Trigger und die erforderlichen Funktionen der Aufgabenstellung implementiert haben, können Sie im Abschnitt if __name__ == '__main__':
damit beginnen, Toots zu filtern. Gehen Sie dabei wie folgt vor:
- Toots laden: Laden Sie zuerst die Toots.
- Trigger und Trigger-Kombinationen definieren: Legen Sie anschließend die gewünschten Trigger und deren Zusammensetzungen fest. Achten Sie darauf, dass Ihre Trigger-Anordnung logisch aufgebaut ist und sich Trigger nicht gegenseitig blockieren. Zum Beispiel sollte ein
AndTrigger
nicht einenBeforeTrigger
(01.01.2024) und einenAfterTrigger
(01.01.2024) kombinieren, da diese sich gegenseitig ausschließen. - Triggerliste aufstellen: Erstellen Sie eine Liste aller Trigger, die Sie überprüfen möchten.
- Filter-Funktion aufrufen: Verwenden Sie die Liste aller Toots und die Triggerliste, um die Funktion
filter_toots
aufzurufen. - Gefilterte Toots ausgeben: Geben Sie abschließend die Toots, welche in der Liste
triggered_toots
sind, auf der Konsole aus. Nutzen Sie hierfür die__str__
-Methode derToot
-Klasse, die Sie zum beginn der Aufgabe implementiert haben.
Testen
Laden Sie Toots basierend auf einem Hashtag herunter, wie im Abschnitt Toots filtern und ausgeben beschrieben, und erstellen Sie entsprechende Trigger-Klassen.
Führen Sie Ihr Programm mit dem folgenden Befehl aus, um die Funktionalität zu testen:
python mastodon_oop.py
Passen Sie anschließend die Trigger sowie deren Kombinationen an, um alle Funktionen Ihres Programms zu testen.
Style
Führen Sie den folgenden Befehl aus, um den Stil Ihres Codes mit style50 zu analysieren:
style50 mastodon_oop.py
Geschafft!
Sie haben es geschafft! Diese Übung war ohne Frage anspruchsvoll, aber Sie haben dabei viele wichtige Konzepte der Softwareentwicklung kennengelernt und praktisch umgesetzt. Von der API-Anbindung über objektorientierte Programmierung bis hin zu flexiblen Filtermechanismen – das sind Fähigkeiten, die Sie in vielen Programmierprojekten gut gebrauchen können.
Wir würden gerne von Ihnen lernen: An welchen Stellen der Aufgabe sind Sie besonders gut vorangekommen? Wo hätten Sie sich mehr Hilfestellung gewünscht? Ihr Feedback hilft uns, die Übung weiter zu verbessern. Nutzen Sie dafür gerne das Kursforum oder sprechen Sie uns in den Tutorien an.