Come posso creare in modo sicuro una directory annidata?

Qual è il modo più elegante per controllare se la directory in cui un file sta per essere scritto esiste, e se no, creare la directory usando Python? Ecco cosa ho provato:

import os

file_path = "/my/directory/filename.txt"
directory = os.path.dirname(file_path)

try:
    os.stat(directory)
except:
    os.mkdir(directory)       

f = file(filename)

In qualche modo, ho mancato os.path.exists (grazie kanja, Blair e Douglas). Questo è quello che ho ora:

def ensure_dir(file_path):
    directory = os.path.dirname(file_path)
    if not os.path.exists(directory):
        os.makedirs(directory)

C'è un flag per "open", che lo fa accadere automaticamente?

Soluzione

Vedo due risposte con buone qualità, ognuna con un piccolo difetto, quindi darò la mia opinione in merito:

Prova os.path.exists, e considera os.makedirs per la creazione.

import os
if not os.path.exists(directory):
    os.makedirs(directory)

Come notato nei commenti e altrove, c'è una condizione di corsa – se la directory viene creata tra le chiamate os.path.exists e os.makedirs, la os.makedirs fallirà con un OSError. Sfortunatamente, catturare un OSError e continuare non è infallibile, poiché ignorerà un fallimento nella creazione della directory dovuto ad altri fattori, come permessi insufficienti, disco pieno, ecc.

Un'opzione sarebbe quella di catturare il OSError ed esaminare il codice di errore incorporato (vedere Esiste un modo multipiattaforma per ottenere informazioni da OSError di Python):

import os, errno

try:
    os.makedirs(directory)
except OSError as e:
    if e.errno != errno.EEXIST:
        raise

In alternativa, potrebbe esserci un secondo os.path.exists, ma supponiamo che un altro abbia creato la directory dopo il primo controllo, poi l'abbia rimossa prima del secondo – potremmo ancora essere ingannati.

A seconda dell'applicazione, il pericolo delle operazioni concomitanti può essere maggiore o minore del pericolo posto da altri fattori come i permessi dei file. Lo sviluppatore dovrebbe conoscere meglio la particolare applicazione da sviluppare e il suo ambiente previsto prima di scegliere un'implementazione.

Le versioni moderne di Python migliorano abbastanza questo codice, sia esponendo FileExistsError (in 3.3+)...

try:
    os.makedirs("path/to/directory")
except FileExistsError:
    # directory already exists
    pass

...e permettendo un argomento parola chiave a os.makedirs chiamato exist_ok (in 3.2+).

os.makedirs("path/to/directory", exist_ok=True)  # succeeds even if directory exists.
Commentari (8)

Controlla os.makedirs: (Si assicura che il percorso completo esista). Per gestire il fatto che la directory potrebbe esistere, cattura un OSError. (Se exist_ok è False (il default), viene sollevato un OSError se la directory di destinazione esiste già).

import os
try:
    os.makedirs('./path/to/somewhere')
except OSError:
    pass
Commentari (3)

Prova la funzione os.path.exists

if not os.path.exists(dir):
    os.mkdir(dir)
Commentari (3)