mitmario.dev

Synthese: Der Aufräumer

Python Sandbox 4 Min Lesezeit 3 BeispieleLektion 7 von 8

Der Download-Ordner ist bei den meisten Leuten der unordentlichste Ort auf dem Rechner. Rechnungen, Fotos, Installationsprogramme, ein Lebenslauf von 2019, alles auf einem Haufen. Das Werkzeug hier sortiert ihn. Bilder kommen nach Bilder, Dokumente nach Dokumente, Archive nach Archive und der Rest nach Sonstiges. Alles, was du dafür brauchst, kam in diesem Abschnitt schon einmal vor, und am Ende hast du ein Werkzeug, das du wirklich benutzen kannst.

Erst aufschreiben, was es tun soll

Wie beim Spritkostenrechner in Lektion 2.7 steht am Anfang ein Plan und noch kein Code.

  1. Den Ordner durchgehen, nach Namen sortiert, und nur Dateien anfassen. Unterordner bleiben, wie sie sind, auch die, die der Aufräumer beim letzten Mal angelegt hat.
  2. Für jede Datei den Zielordner aus ihrer Endung bestimmen.
  3. Den Zielordner anlegen, falls es ihn noch nicht gibt, und die Datei hineinschieben.
  4. Mitzählen, was wohin gegangen ist, und am Ende eine Zeile dazu ausgeben.
  5. Das alles nur dann wirklich, wenn man es beim Start ausdrücklich sagt. Sonst wird nur angezeigt, was passieren würde.

Der letzte Punkt ist der wichtigste. Mit ihm geht es los.

Ein Schalter beim Start

Ein Schalter für den echten Lauf
import sys

wirklich = "--wirklich" in sys.argv
print(sys.argv)
if wirklich:
    print("Jetzt wird verschoben.")
else:
    print("Probelauf, es wird nichts verschoben.")

Beim Umbenennen hing der Probelauf an einer Variablen im Code. Für ein Werkzeug ist das unpraktisch, weil man für jeden echten Lauf die Datei ändern müsste und hinterher wieder zurück, und das vergisst man.

Besser ist ein Schalter (flag) beim Start, so wie bei den Argumenten der Kommandozeile. python main.py ist dann der Probelauf, python main.py --wirklich der echte. Die zwei Striche vorn sind die übliche Form für einen Schalter mit einem ganzen Wort.

Mit "--wirklich" in sys.argv wird gefragt, ob der Schalter irgendwo in der Liste steht. Das ist sicherer als sys.argv[1] == "--wirklich", weil es ohne Argument keine Position 1 gibt und der Probelauf dann mit einem IndexError enden würde. Den zweiten Start findest du in der Befehlsleiste.

Wichtig ist die Richtung. Ohne Schalter passiert nichts, und wenn du ihn vergisst, bekommst du nur eine Liste zu lesen. Andersherum, mit einem Schalter --probelauf, wäre ausgerechnet das Vergessen der Fehler, bei dem Dateien verschoben werden.

Nur Dateien

Was im Download-Ordner liegt
from pathlib import Path

for eintrag in sorted(Path("downloads").iterdir()):
    if not eintrag.is_file():
        print("Keine Datei, bleibt liegen:", eintrag.name)
        continue
    print(eintrag.name, "hat die Endung", eintrag.suffix.lower())

Im Ordner liegt schon ein Unterordner Bilder, vom letzten Aufräumen. Ohne die Frage nach is_file() hätte er die Endung "" und würde nach Sonstiges geschoben, samt den Fotos darin. Deshalb wird mit continue alles übersprungen, was keine Datei ist. Die Endung kommt mit lower(), damit .PDF und .pdf dasselbe sind.

Den Zielordner legt mkdir(exist_ok=True) an. Wenn es ihn schon gibt, wie hier Bilder, ist das kein Fehler, und die Datei kommt einfach dazu. Ohne exist_ok endet schon der erste Lauf mit einem FileExistsError, sobald die zweite Datei in denselben Ordner soll.

Zu Hause benutzen

Für deinen echten Download-Ordner ersetzt du Path("downloads") durch Path.home() / "Downloads". Path.home() ist dein persönlicher Ordner, unter Windows etwa C:\Users\mia, auf dem Mac /Users/mia. Mehr ändert sich nicht.

Bevor das Werkzeug zum ersten Mal an echte Dateien geht, kopierst du den Ordner und lässt es auf die Kopie los. Erst als Probelauf. Dann liest du die Liste, startest mit --wirklich und schaust in der Kopie nach. Ein Programm, das Dateien verschiebt, macht einen Fehler eben bei allen Dateien zugleich.

Wenn es zuverlässig läuft, kann die Aufgabenplanung es jeden Freitag starten. Dann aber mit --wirklich als Argument, sonst gibt es jeden Freitag einen Probelauf, den niemand liest.

Zweimal derselbe Name
import shutil
from pathlib import Path

for datei in sorted(Path("downloads").glob("*.jpg")):
    shutil.move(datei, "downloads/Bilder")
    print(datei.name, "liegt jetzt in Bilder")

Eine Sache fehlt dem Aufräumer der Aufgabe noch, und die gehört nachgerüstet, bevor er zu Hause von allein läuft. Wenn im Zielordner schon eine Datei mit demselben Namen liegt, etwa ein strand.jpg vom letzten Sommer, verweigert shutil.move den Dienst mit shutil.Error: Destination path 'downloads/Bilder/strand.jpg' already exists.

Der Hafen davor ist dann schon verschoben, alles danach nicht mehr, und der Ordner ist halb aufgeräumt. Was dagegen hilft, kennst du aus Lektion 11.6. Vorher mit exists() nachsehen und die Datei mit einer Meldung liegen lassen.

Was die Aufgabe will

Gebaut wird dieses Werkzeug für den Ordner downloads. Ohne Schalter ist es ein Probelauf, mit --wirklich wird verschoben. In beiden Fällen steht am Ende da, wie viele Dateien in welchen Ordner gehören.

Zum Mitnehmen

Der Aufräumer geht den Download-Ordner durch und sucht für jede Datei nach ihrer Endung den passenden Unterordner aus. Fehlt der Ordner, wird er angelegt, und dann wird die Datei verschoben. Ohne --wirklich beim Start ist alles nur ein Probelauf, und am Ende steht da, was passieren würde.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.