Come posso ottenere la directory principale in Python?


350

Qualcuno potrebbe dirmi come ottenere la directory principale di un percorso in Python in modo multipiattaforma. Per esempio

C:\Program Files ---> C:\

e

C:\ ---> C:\

Se la directory non ha una directory padre, restituisce la directory stessa. La domanda potrebbe sembrare semplice ma non sono riuscito a cercarla su Google.

Risposte:


481

Aggiornamento da Python 3.4

Usa il pathlibmodulo.

from pathlib import Path
path = Path("/here/your/path/file.txt")
print(path.parent)

Vecchia risposta

Prova questo:

import os.path
print os.path.abspath(os.path.join(yourpath, os.pardir))

dov'è yourpathil percorso per cui desideri il genitore.


137
La tua risposta è corretta ma contorta; os.path.dirnameè la funzione per questo, come a+=5-4è più contorto di a+=1. La domanda richiedeva solo la directory principale, non se esiste o la directory principale vera presupponendo che i collegamenti simbolici si frappongano.
tzot

16
Non lo os.pardirè os.path.pardir.
bouteillebleu,

9
@bouteillebleu: entrambi os.pardire in os.path.pardirrealtà sono corretti (sono identici).
Eric O Lebigot,

45
@tzot: sfortunatamente os.path.dirnamedà risultati diversi a seconda che nel percorso sia inclusa una barra finale. Se desideri risultati affidabili, devi utilizzare il os.path.joinmetodo nella risposta sopra.
Artfunkel,

21
Poiché questo è apparentemente abbastanza complicato da giustificare una domanda StackOverflow, ritengo che questo dovrebbe essere aggiunto alla libreria os.path come funzione integrata.
Antred

324

Utilizzando os.path.dirname:

>>> os.path.dirname(r'C:\Program Files')
'C:\\'
>>> os.path.dirname('C:\\')
'C:\\'
>>>

Avvertenza: os.path.dirname()fornisce risultati diversi a seconda che nel percorso sia inclusa una barra finale. Questa potrebbe essere o meno la semantica che desideri. Cf. @ kender's answer using os.path.join(yourpath, os.pardir).


6
os.path.dirname(r'C:\Program Files')che cosa? Python ti sta semplicemente fornendo la directory in cui si trova il file "Programmi". Inoltre, non deve nemmeno esistere, ecco: os.path.dirname(r'c:\i\like\to\eat\pie')uscite'c:\\i\\like\\to\\eat'
Nick T,

41
Il poster originale non indica che la directory deve esistere. Esistono molti metodi di percorso che non fanno altro che manipolare le stringhe. Per verificare se il percorso esiste effettivamente richiede un accesso al disco. Dipende dall'applicazione che può essere o non essere desiderabile.
Wai Yip Tung,

10
questa soluzione è sensibile al trascinamento di os.sep. Pronuncia os.sep == '/'. dirname (foo / bar) -> foo, ma dirname (foo / bar /) -> foo / bar
marcin

6
Questo è di progettazione. Dipende dall'interpretazione di un percorso con un trailing /. Consideri "path1" uguale a "path1 /"? La biblioteca usa l'interpretazione più generale che sono distinti. In alcuni contesti le persone potrebbero volerli trattare come equivalenti. In questo caso puoi prima fare una rstrip ('/'). Se la biblioteca scegliesse l'altra interpretazione, perderai fedeltà.
Wai Yip Tung,

3
@Ryan, non lo so. C'è un intero RFC 1808 scritto per affrontare il problema del percorso relativo in URI e tutta la sottigliezza della presenza e assenza di un trascinamento /. Se conosci documenti che affermano che dovrebbero essere trattati in modo equivalente in generale, segnalalo.
Wai Yip Tung,

112

Il metodo Pathlib (Python 3.4+)

from pathlib import Path
Path('C:\Program Files').parent
# Returns a Pathlib object

Il metodo tradizionale

import os.path
os.path.dirname('C:\Program Files')
# Returns a string


Quale metodo dovrei usare?

Utilizzare il metodo tradizionale se:

  • Sei preoccupato che il codice esistente generi errori se dovesse usare un oggetto Pathlib. (Poiché gli oggetti Pathlib non possono essere concatenati con stringhe.)

  • La tua versione di Python è inferiore a 3.4.

  • Hai bisogno di una stringa e hai ricevuto una stringa. Supponiamo ad esempio che tu abbia una stringa che rappresenta un percorso file e desideri ottenere la directory principale in modo da poterla inserire in una stringa JSON. Sarebbe una specie di sciocco da convertire in un oggetto Pathlib e viceversa.

Se nessuna delle precedenti condizioni si applica, utilizzare Pathlib.



Che cos'è Pathlib?

Se non sai cos'è Pathlib, il modulo Pathlib è un formidabile modulo che ti semplifica ulteriormente l'utilizzo dei file. La maggior parte se non tutti i moduli Python integrati che funzionano con i file accetteranno sia oggetti sia stringhe Pathlib. Di seguito ho evidenziato un paio di esempi della documentazione Pathlib che mostrano alcune delle cose interessanti che puoi fare con Pathlib.

Navigazione all'interno di un albero di directory:

>>> p = Path('/etc')
>>> q = p / 'init.d' / 'reboot'
>>> q
PosixPath('/etc/init.d/reboot')
>>> q.resolve()
PosixPath('/etc/rc.d/init.d/halt')

Proprietà del percorso di query:

>>> q.exists()
True
>>> q.is_dir()
False

4
Questa è l'unica risposta sana. Se sei costretto a usare Python 2, basta pip install pathlib2usare il backport.
Navin,

1
Questa soluzione NON è sensibile al trascinamento os.sep!
Dylan F,

35
import os
p = os.path.abspath('..')

C:\Program Files ---> C:\\\

C:\ ---> C:\\\


7
Questo ottiene solo il genitore del CWD, non il genitore di un percorso arbitrario come richiesto dall'OP.
Sergio,

Aggiungi i punti doppi alla fine del tuo URL e funzionerà Ad esempio os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') Risultato:E:\\O3M_Tests_Embedded\\branches
Arindam Roychowdhury

Ciò significa: /.
Loretoparisi,

26

Una soluzione alternativa di @kender

import os
os.path.dirname(os.path.normpath(yourpath))

dov'è yourpathil percorso per cui desideri il genitore.

Ma questa soluzione non è perfetta, dal momento che non gestirà il caso in cui yourpathè una stringa vuota o un punto.

Quest'altra soluzione gestirà più bene questo caso d'angolo:

import os
os.path.normpath(os.path.join(yourpath, os.pardir))

Ecco le uscite per ogni caso che può trovare (il percorso di input è relativo):

os.path.dirname(os.path.normpath('a/b/'))          => 'a'
os.path.normpath(os.path.join('a/b/', os.pardir))  => 'a'

os.path.dirname(os.path.normpath('a/b'))           => 'a'
os.path.normpath(os.path.join('a/b', os.pardir))   => 'a'

os.path.dirname(os.path.normpath('a/'))            => ''
os.path.normpath(os.path.join('a/', os.pardir))    => '.'

os.path.dirname(os.path.normpath('a'))             => ''
os.path.normpath(os.path.join('a', os.pardir))     => '.'

os.path.dirname(os.path.normpath('.'))             => ''
os.path.normpath(os.path.join('.', os.pardir))     => '..'

os.path.dirname(os.path.normpath(''))              => ''
os.path.normpath(os.path.join('', os.pardir))      => '..'

os.path.dirname(os.path.normpath('..'))            => ''
os.path.normpath(os.path.join('..', os.pardir))    => '../..'

Il percorso di input è assoluto (percorso Linux):

os.path.dirname(os.path.normpath('/a/b'))          => '/a'
os.path.normpath(os.path.join('/a/b', os.pardir))  => '/a'

os.path.dirname(os.path.normpath('/a'))            => '/'
os.path.normpath(os.path.join('/a', os.pardir))    => '/'

os.path.dirname(os.path.normpath('/'))             => '/'
os.path.normpath(os.path.join('/', os.pardir))     => '/'

La normalizzazione del percorso è sempre una buona pratica, specialmente quando si fa un lavoro multipiattaforma.
DevPlayer

Questa è la risposta corretta! Mantiene relativi percorsi relativi. Grazie!
Massimo

@Maxim Questa soluzione non era perfetta, l'ho migliorata poiché la soluzione originale non gestisce un caso
benjarobin,

@benjarobin Sì, non avevo pensato al caso d'angolo. Grazie.
Massima

18
os.path.split(os.path.abspath(mydir))[0]

Questo non funzionerà per i percorsi che si trovano in una directory, ma restituirà nuovamente la directory.
Anthony Briggs,

2
@AnthonyBriggs, l'ho appena provato usando Python 2.7.3 su Ubuntu 12.04 e sembra funzionare bene. os.path.split(os.path.abspath("this/is/a/dir/"))[0]ritorna '/home/daniel/this/is/a'come previsto. Al momento non ho una finestra di Windows in esecuzione per controllare lì. In quale configurazione hai osservato il comportamento segnalato?
Dan Menes,

Si potrebbe fare parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]. Questo - ne sono certo - funziona perché se c'è una barra all'estremità, viene rimossa; se non c'è barra, funzionerà comunque (anche se l'ultima parte del percorso è lunga solo un carattere) a causa della barra precedente. Questo ovviamente presuppone che il percorso sia corretto e non dica qualcosa di simile /a//b/c///d////(in unix questo è ancora valido), che nella maggior parte dei casi sono (corretti) soprattutto quando si fa qualcosa di simile os.path.abspatho qualsiasi altra os.pathfunzione.
dylnmc,

Inoltre, per contrastare molte barre alla fine, potresti semplicemente scrivere un piccolo ciclo per rimuoverle. Sono sicuro che potrebbe esserci anche un one-liner intelligente per farlo, o forse farlo e os.path.split in una riga.
dylnmc,

@ Men Men, ti ho appena visto commentare. Non funziona se hai qualcosa di simile os.path.split("a/b//c/d///")e, ad esempio, cd //////dev////// is equivalent to cd / dev / `oppure cd /dev; tutti questi sono validi in Linux. Ho appena arrivato fino a questo e può essere utile, però: os.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]. (Questo essenzialmente cerca l'ultimo non-slash, e ottiene la sottostringa del percorso fino a quel carattere.) Ho usato path = "/a//b///c///d////"e quindi ho eseguito la dichiarazione di cui sopra e ho ottenuto '/a//b///c'.
dylnmc,

14
os.path.abspath(os.path.join(somepath, '..'))

Osservare:

import posixpath
import ntpath

print ntpath.abspath(ntpath.join('C:\\', '..'))
print ntpath.abspath(ntpath.join('C:\\foo', '..'))
print posixpath.abspath(posixpath.join('/', '..'))
print posixpath.abspath(posixpath.join('/home', '..'))

7
import os
print"------------------------------------------------------------"
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
print("example 1: "+SITE_ROOT)
PARENT_ROOT=os.path.abspath(os.path.join(SITE_ROOT, os.pardir))
print("example 2: "+PARENT_ROOT)
GRANDPAPA_ROOT=os.path.abspath(os.path.join(PARENT_ROOT, os.pardir))
print("example 3: "+GRANDPAPA_ROOT)
print "------------------------------------------------------------"

6

Se si desidera solo il nome della cartella che è il genitore immediato del file fornito come argomento e non il percorso assoluto di quel file:

os.path.split(os.path.dirname(currentDir))[1]

cioè con un currentDirvalore di/home/user/path/to/myfile/file.ext

Il comando sopra restituirà:

myfile


3
os.path.basename (os.path.dirname (current_dir)) funziona anche qui.
DevPlayer,

4
>>> import os
>>> os.path.basename(os.path.dirname(<your_path>))

Ad esempio in Ubuntu:

>>> my_path = '/home/user/documents'
>>> os.path.basename(os.path.dirname(my_path))
# Output: 'user'

Ad esempio in Windows:

>>> my_path = 'C:\WINDOWS\system32'
>>> os.path.basename(os.path.dirname(my_path))
# Output: 'WINDOWS'

Entrambi gli esempi hanno provato in Python 2.7


3
import os.path

os.path.abspath(os.pardir)

Ciò presuppone che si desideri che la directory padre della "directory di lavoro corrente" e non la directory padre in alcun percorso in generale.
DevPlayer

3

Supponiamo di avere una struttura di directory simile

1]

/home/User/P/Q/R

Vogliamo accedere al percorso di "P" dalla directory R, ​​quindi possiamo accedere utilizzando

ROOT = os.path.abspath(os.path.join("..", os.pardir));

2]

/home/User/P/Q/R

Vogliamo accedere al percorso della directory "Q" dalla directory R, ​​quindi possiamo accedere utilizzando

ROOT = os.path.abspath(os.path.join(".", os.pardir));

2

Basta aggiungere qualcosa alla risposta di Tung (devi usare rstrip('/') per essere più sicuro se sei su una casella unix).

>>> input = "../data/replies/"
>>> os.path.dirname(input.rstrip('/'))
'../data'
>>> input = "../data/replies"
>>> os.path.dirname(input.rstrip('/'))
'../data'

Ma se non lo usi rstrip('/') , dato il tuo input è

>>> input = "../data/replies/"

sarebbe uscita,

>>> os.path.dirname(input)
'../data/replies'

che probabilmente non è quello che stai guardando come vuoi entrambi "../data/replies/"e "../data/replies"comportarti allo stesso modo.


1
Consiglierei di non usare "input" come variabile / riferimento. È una funzione integrata.
DevPlayer

2
import os

dir_path = os.path.dirname(os.path.realpath(__file__))
parent_path = os.path.abspath(os.path.join(dir_path, os.pardir))

1
print os.path.abspath(os.path.join(os.getcwd(), os.path.pardir))

Puoi usarlo per ottenere la directory principale della posizione corrente del tuo file py.


2
Quel suggerimento porta spesso a bug. os.getcwd () spesso NON è il "file py". Pensa ai pacchetti. Se "importare some_package_with_subpackages" molti moduli non saranno nella directory più in alto di quel pacchetto. os.getcwd () restituisce dove si esegue lo script più in alto. E questo presuppone anche che lo stai facendo da una riga di comando.
DevPlayer

0

OTTIENI il percorso della directory principale e crea una nuova directory (nome new_dir)

Ottieni percorso directory principale

os.path.abspath('..')
os.pardir

Esempio 1

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.pardir, 'new_dir'))

Esempio 2

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.path.abspath('..'), 'new_dir'))


0
import os

def parent_filedir(n):
    return parent_filedir_iter(n, os.path.dirname(__file__))

def parent_filedir_iter(n, path):
    n = int(n)
    if n <= 1:
        return path
    return parent_filedir_iter(n - 1, os.path.dirname(path))

test_dir = os.path.abspath(parent_filedir(2))

0

Le risposte fornite sopra sono tutte perfettamente valide per salire di uno o due livelli di directory, ma possono diventare un po 'ingombranti se si deve attraversare l'albero di directory di molti livelli (diciamo 5 o 10). Questo può essere fatto concisamente unendo un elenco di N os.pardirs in os.path.join. Esempio:

import os
# Create list of ".." times 5
upup = [os.pardir]*5
# Extract list as arguments of join()
go_upup = os.path.join(*upup)
# Get abspath for current file
up_dir = os.path.abspath(os.path.join(__file__, go_upup))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.