Comment obtenir le répertoire parent en Python?

350

Quelqu'un pourrait-il me dire comment obtenir le répertoire parent d'un chemin d'accès en Python d'une manière multiplateforme. Par exemple

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

et

C:\ ---> C:\

Si le répertoire n'a pas de répertoire parent, il renvoie le répertoire lui-même. La question peut sembler simple, mais je n'ai pas pu la découvrir via Google.

Mridang Agarwalla
la source

Réponses:

481

Mise à jour depuis Python 3.4

Utilisez le pathlibmodule.

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

Ancienne réponse

Essaye ça:

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

yourpathest le chemin pour lequel vous voulez que le parent.

kender
la source
137
Votre réponse est correcte mais alambiquée; os.path.dirnameest la fonction pour cela, comme a+=5-4est plus compliquée que a+=1. La question demandait seulement le répertoire parent, pas s'il existe ou le vrai répertoire parent en supposant que les liens symboliques gênent.
tzot
16
Ce n'est os.pardirpas le cas os.path.pardir.
bouteillebleu
9
@bouteillebleu: Les deux os.pardiret os.path.pardirsont en fait corrects (ils sont identiques).
Eric O Lebigot
45
@tzot: os.path.dirnamedonne malheureusement des résultats différents selon que la barre oblique est incluse dans le chemin. Si vous voulez des résultats fiables, vous devez utiliser la os.path.joinméthode décrite ci-dessus.
Artfunkel
21
Comme cela est apparemment assez compliqué pour justifier une question StackOverflow, je pense que cela devrait être ajouté à la bibliothèque os.path en tant que fonction intégrée.
entrée
324

En utilisant os.path.dirname:

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

Avertissement: os.path.dirname()donne des résultats différents selon que la barre oblique de fin est incluse dans le chemin. Cela peut ou non être la sémantique souhaitée. Cf. @ kender's answer using os.path.join(yourpath, os.pardir).

Wai Yip Tung
la source
6
os.path.dirname(r'C:\Program Files')quelle? Python vous donne juste le répertoire où le fichier «Program Files» serait. De plus, il n'a même pas besoin d'exister, voici: os.path.dirname(r'c:\i\like\to\eat\pie')sorties'c:\\i\\like\\to\\eat'
Nick T
41
L'affiche originale n'indique pas que le répertoire doit exister. Il existe de nombreuses méthodes de chemin d'accès qui ne font que manipuler les chaînes. Pour vérifier si le nom de chemin existe réellement, il faut un accès au disque. Selon l'application, cela peut être souhaitable ou non.
Wai Yip Tung
10
cette solution est sensible à la fuite os.sep. Dites os.sep == '/'. dirname (foo / bar) -> foo, mais dirname (foo / bar /) -> foo / bar
marcin
6
C'est par conception. Cela revient à interpréter un chemin avec un /. Considérez-vous que "chemin1" est égal à "chemin1 /"? La bibliothèque utilise l'interprétation la plus générale selon laquelle ils sont distincts. Dans certains contextes, les gens peuvent vouloir les traiter comme équivalents. Dans ce cas, vous pouvez d'abord faire une rstrip ('/'). Si la bibliothèque avait choisi l'autre interprétation, vous perdriez la fidélité.
Wai Yip Tung
3
@Ryan, je n'en sais rien. Il existe un RFC 1808 complet écrit pour résoudre le problème du chemin relatif dans l'URI et toute la subtilité de la présence et de l'absence d'un /. Si vous connaissez des documents qui disent qu'ils devraient être traités de manière équivalente en général, veuillez le signaler.
Wai Yip Tung
112

La méthode Pathlib (Python 3.4+)

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

La méthode traditionnelle

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


Quelle méthode dois-je utiliser?

Utilisez la méthode traditionnelle si:

  • Vous vous inquiétez des erreurs de génération de code existantes si elle devait utiliser un objet Pathlib. (Étant donné que les objets Pathlib ne peuvent pas être concaténés avec des chaînes.)

  • Votre version Python est inférieure à 3.4.

  • Vous avez besoin d'une chaîne et vous avez reçu une chaîne. Supposons par exemple que vous avez une chaîne représentant un chemin de fichier et que vous souhaitez obtenir le répertoire parent afin de pouvoir le placer dans une chaîne JSON. Il serait assez idiot de se convertir en objet Pathlib et de revenir pour cela.

Si aucun des éléments ci-dessus ne s'applique, utilisez Pathlib.



Qu'est-ce que Pathlib?

Si vous ne savez pas ce qu'est Pathlib, le module Pathlib est un module formidable qui rend le travail avec des fichiers encore plus facile pour vous. La plupart, sinon la totalité, des modules Python intégrés qui fonctionnent avec des fichiers accepteront à la fois les objets et les chaînes Pathlib. J'ai mis en évidence ci-dessous quelques exemples de la documentation Pathlib qui présentent certaines des choses intéressantes que vous pouvez faire avec Pathlib.

Navigation dans une arborescence de répertoires:

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

Interrogation des propriétés du chemin:

>>> q.exists()
True
>>> q.is_dir()
False
wp-overwatch.com
la source
4
Ceci est la seule réponse sensée. Si vous êtes obligé d'utiliser Python 2, pip install pathlib2utilisez simplement le backport.
Navin
1
Cette solution n'est PAS sensible à la fuite os.sep!
Dylan F
35
import os
p = os.path.abspath('..')

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

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

ivo
la source
7
Cela n'obtient que le parent du CWD, pas le parent d'un chemin arbitraire comme l'OP l'a demandé.
Sergio
Ajoutez les points doubles à la fin de votre URL et cela fonctionnera Par exemple os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') :E:\\O3M_Tests_Embedded\\branches
Arindam Roychowdhury
Cela signifie: /.
loretoparisi
26

Une solution alternative de @kender

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

yourpathest le chemin pour lequel vous voulez que le parent.

Mais cette solution n'est pas parfaite, car elle ne gérera pas le cas où se yourpathtrouve une chaîne vide ou un point.

Cette autre solution gérera mieux ce cas d'angle:

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

Voici les sorties pour chaque cas qui peut trouver (le chemin d'entrée est relatif):

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))    => '../..'

Le chemin d'entrée est absolu (chemin 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))     => '/'
benjarobin
la source
La normalisation du chemin est toujours une bonne pratique, en particulier lors d'un travail multiplateforme.
DevPlayer
Ceci est la bonne réponse! Il garde les chemins relatifs relatifs. Merci!
Maxim
@Maxim Cette solution n'était pas parfaite, je l'ai améliorée car la solution originale ne gère pas un cas
benjarobin
@benjarobin Oui, je n'avais pas pensé à la valise d'angle. Merci.
Maxim
18
os.path.split(os.path.abspath(mydir))[0]
Dan Menes
la source
Cela ne fonctionnera pas pour les chemins qui se trouvent dans un répertoire, il retournera simplement le répertoire à nouveau.
Anthony Briggs
2
@AnthonyBriggs, je viens d'essayer ceci en utilisant Python 2.7.3 sur Ubuntu 12.04 et cela semble bien fonctionner. os.path.split(os.path.abspath("this/is/a/dir/"))[0]renvoie '/home/daniel/this/is/a'comme prévu. Pour le moment, je n'ai pas de boîte Windows en cours d'exécution à vérifier. Sur quelle configuration avez-vous observé le comportement que vous signalez?
Dan Menes
Tu pourrais faire parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]. Cela - j'en suis certain - fonctionne parce que s'il y a une barre oblique à la fin, elle est supprimée; s'il n'y a pas de barre oblique, cela fonctionnera toujours (même si la dernière partie du chemin ne comporte qu'un caractère) en raison de la barre oblique précédente. Bien sûr, cela suppose que le chemin est correct et ne dit pas quelque chose comme /a//b/c///d////(sous Unix, cela est toujours valable), ce qui dans la plupart des cas, il est (approprié), surtout lorsque vous faites quelque chose comme os.path.abspathou toute autre os.pathfonction.
dylnmc
De plus, pour contrer beaucoup de barres obliques à la fin, vous pouvez simplement écrire une petite boucle for qui les supprime. Je suis sûr qu'il pourrait même y avoir un one-liner intelligent pour le faire, ou peut-être le faire et os.path.split en une seule ligne.
dylnmc
@Den Menes Je viens de te voir commenter. Cela ne fonctionne pas si vous avez quelque chose comme os.path.split("a/b//c/d///")et, par exemple, cd //////dev////// is equivalent to cd / dev / `ou cd /dev; tous ces éléments sont valides sous linux. Je suis venu avec cela et il peut être utile, si: os.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]. (Cela recherche essentiellement la dernière non-barre oblique et obtient la sous-chaîne du chemin jusqu'à ce caractère.) J'ai utilisé path = "/a//b///c///d////"puis exécuté la déclaration susmentionnée et obtenu '/a//b///c'.
dylnmc
14
os.path.abspath(os.path.join(somepath, '..'))

Observer:

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', '..'))
Ignacio Vazquez-Abrams
la source
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 "------------------------------------------------------------"
Grand-papa
la source
6

Si vous souhaitez uniquement le nom du dossier qui est le parent immédiat du fichier fourni en argument et non le chemin absolu de ce fichier:

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

c'est-à-dire avec une currentDirvaleur de/home/user/path/to/myfile/file.ext

La commande ci-dessus renverra:

myfile

8bitjunkie
la source
3
os.path.basename (os.path.dirname (current_dir)) fonctionne également ici.
DevPlayer
4
>>> import os
>>> os.path.basename(os.path.dirname(<your_path>))

Par exemple dans Ubuntu:

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

Par exemple sous Windows:

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

Les deux exemples ont essayé en Python 2.7

Soumendra
la source
3
import os.path

os.path.abspath(os.pardir)
Washington Botelho
la source
Cela suppose que vous souhaitiez que le répertoire parent du "répertoire de travail en cours" et non le répertoire parent un chemin en général.
DevPlayer
3

Supposons que nous ayons une structure de répertoires comme

1]

/home/User/P/Q/R

On veut accéder au chemin de "P" depuis le répertoire R alors on peut y accéder en utilisant

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

2]

/home/User/P/Q/R

Nous voulons accéder au chemin du répertoire "Q" à partir du répertoire R alors nous pouvons y accéder en utilisant

ROOT = os.path.abspath(os.path.join(".", os.pardir));
Rakesh Chaudhari
la source
2

Il suffit d'ajouter quelque chose à la réponse de Tung (vous devez utiliser rstrip('/')pour être plus sûr si vous êtes sur une boîte Unix).

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

Mais, si vous n'utilisez pas rstrip('/'), étant donné que votre entrée est

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

produirait,

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

ce qui n'est probablement pas ce que vous regardez car vous voulez les deux "../data/replies/"et "../data/replies"vous comporter de la même manière.

samsamara
la source
1
Je recommanderais de ne pas utiliser "input" comme variable / référence. C'est une fonction intégrée.
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))
Miguel Mota
la source
1
print os.path.abspath(os.path.join(os.getcwd(), os.path.pardir))

Vous pouvez l'utiliser pour obtenir le répertoire parent de l'emplacement actuel de votre fichier py.

Eros Nikolli
la source
2
Cette suggestion conduit souvent à des bugs. os.getcwd () n'est souvent PAS où se trouve "votre fichier py". Pensez aux packages. Si j'importe "certains_packages_avec_sous-packages", de nombreux modules ne seront pas dans le répertoire le plus haut de ce package. os.getcwd () retourne où vous exécutez le script le plus haut. Et cela suppose également que vous le faites à partir d'une ligne de commande.
DevPlayer
0

OBTENIR le chemin du répertoire parent et créer un nouveau répertoire (nom new_dir)

Obtenir le chemin du répertoire parent

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

Exemple 1

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

Exemple 2

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.path.abspath('..'), 'new_dir'))
Jay Patel
la source
0
os.path.abspath('D:\Dir1\Dir2\..')

>>> 'D:\Dir1'

Donc ça ..aide

Arindam Roychowdhury
la source
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))
fuyunliu
la source
0

Les réponses données ci-dessus sont toutes parfaitement adaptées pour monter d'un ou deux niveaux de répertoire, mais elles peuvent devenir un peu lourdes si l'on a besoin de parcourir l'arborescence de répertoires de plusieurs niveaux (disons, 5 ou 10). Cela peut être fait de manière concise en joignant une liste de N os.pardirs dans os.path.join. Exemple:

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))
MPA
la source