Python: Wie legt man ein Verzeichnis samt fehlender Elternverzeichnisse an?
Ein Verzeichnis anzulegen ist ein Aufruf. Eines mehrere Ebenen tief anzulegen, ohne zu scheitern wenn es schon da ist und ohne Race Condition, braucht zwei Schlüsselwortargumente die man leicht vergisst.
Die Antwort
from pathlib import Path
Path("/tmp/a/b/c").mkdir(parents=True, exist_ok=True)
exists : True
is_dir : True
Beide Schlüsselwörter verdienen ihren Platz. Ohne parents=True ist ein
fehlendes Zwischenverzeichnis ein Fehler:
mkdir() with a missing parent -> FileNotFoundError: [Errno 2] No such file or directory: '/tmp/demo0049/x/y'
Und ohne exist_ok=True ist ein bereits vorhandenes Verzeichnis ein Fehler:
mkdir(parents=True) on an existing dir -> FileExistsError: [Errno 17] File exists: '/tmp/demo0049/a/b/c'
Das Gegenstück aus os
ist os.makedirs(pfad, exist_ok=True), wobei makedirs das parents=True
schon impliziert. Beides ist in Ordnung;
pathlib liest sich besser,
sobald du im selben Code auch Pfade zusammensetzt und Dateien liest.
Warum man nicht vorher prüft
Die Variante, die man ohne nachzudenken schreibt:
if not pfad.exists():
pfad.mkdir()
Zwischen dem exists() und dem mkdir() kann ein anderer Prozess das
Verzeichnis anlegen — und dann wirft dein mkdir() genau den Fehler, den du
vermeiden wolltest. Das ist ein Check-then-act-Rennen, und es geht selten genug
schief, um rätselhaft zu sein.
exist_ok=True schiebt die ganze Sache in einen einzigen Systemaufruf, in dem
der Kernel das entscheidet. Dasselbe Prinzip wie try/except statt
if exists: die Sache tun und den Fehlschlag behandeln, statt eine Frage zu
stellen, deren Antwort sofort veraltet.
exist_ok=True heißt nicht “falls dort irgendetwas ist”
Das sollte man wissen, denn der Name legt etwas anderes nahe. Leg eine Datei an diesen Pfad:
a FILE at the path, mkdir(exist_ok=True) -> FileExistsError: [Errno 17] File exists: '/tmp/demo0049/clash'
exist_ok=True duldet ein vorhandenes Verzeichnis. Alles andere an diesem
Pfad bleibt ein Fehler — was richtig so ist, und was man wissen sollte, wenn man
versucht ist, es als “stell sicher dass dieser Pfad benutzbar ist” zu lesen.
Rechte, und die beiden Überraschungen
mkdir() nimmt ein mode entgegen, und der Wert den du übergibst ist nicht
der Wert den du bekommst:
mkdir(mode=0o700) -> drwx------
mkdir(mode=0o777) -> drwxr-xr-x
current umask : 0o22
Der Modus wird mit der umask des Prozesses maskiert, 0o777 ergibt bei der
üblichen umask 0o022 also 0o755. Das ist normales Unix-Verhalten und keine
Python-Eigenart, erwischt aber jeden, der einen Modus setzt und danach
nachsieht.
Die zweite Überraschung ist spezifischer:
with parents=True, the PARENT gets the default mode, not yours:
parent drwxr-xr-x inner drwx------
In einem Aufruf mit mode=0o700, parents=True angelegt — den Modus hat nur das
unterste Verzeichnis bekommen. Die Elternverzeichnisse entstanden mit der
Voreinstellung. Wer einen Baum aufbaut, der privat sein soll, hat die
Zwischenverzeichnisse also offen, und gewarnt wird man nicht.
Setz die Rechte anschließend explizit, wenn es darauf ankommt, mit
Path.chmod.
Der Fall, den man tatsächlich hat
In neun von zehn Fällen willst du gleich eine Datei schreiben, und ihr Verzeichnis gibt es womöglich noch nicht:
zieldatei = Path("berichte") / "2026" / "aus.txt"
zieldatei.parent.mkdir(parents=True, exist_ok=True)
zieldatei.write_text("fertig\n")
.parent ist der ganze Kniff — du hast den Dateipfad und brauchst das
Verzeichnis darum herum.
Wenn es wieder weg soll
Ist das Verzeichnis temporär, überlass die Arbeit Python:
with tempfile.TemporaryDirectory() as tmp:
...
inside the with block : True
after the with block : False
tempfile.TemporaryDirectory
räumt den Baum beim Verlassen weg, auch bei einer Exception. Deutlich besser
als ein selbst gebauter Pfad in /tmp, der jeden Absturz überlebt.
Beim Löschen von Hand gibt es eine Asymmetrie, die man sich merken sollte:
Path.rmdir() only removes an EMPTY directory:
-> OSError: [Errno 39] Directory not empty
rmdir() verweigert ein nicht-leeres Verzeichnis.
shutil.rmtree
entfernt den ganzen Baum ohne nachzufragen — was genau so gefährlich ist, wie
es klingt.
Hinweis zu Netcup (Werbung)
Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).