¿Cómo obtengo el directorio padre en Python?

350

¿Podría alguien decirme cómo obtener el directorio principal de una ruta en Python de una manera multiplataforma? P.ej

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

y

C:\ ---> C:\

Si el directorio no tiene un directorio padre, devuelve el directorio en sí. La pregunta puede parecer simple, pero no pude desenterrarla a través de Google.

Mridang Agarwalla
fuente

Respuestas:

481

Actualización de Python 3.4

Usa el pathlibmódulo.

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

Vieja respuesta

Prueba esto:

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

¿Dónde yourpathestá la ruta para la que desea el padre?

kender
fuente
137
Su respuesta es correcta pero enrevesada; os.path.dirnamees la función para esto, como a+=5-4es más complicado que a+=1. La pregunta solicitó solo el directorio padre, no si existe o el directorio padre verdadero suponiendo que los enlaces simbólicos se interpongan en el camino.
tzot
16
Es os.pardir, no os.path.pardir.
bouteillebleu
99
@bouteillebleu: Ambos os.pardiry os.path.pardirson realmente correctos (son idénticos).
Eric O Lebigot
45
@tzot: desafortunadamente os.path.dirnameda resultados diferentes dependiendo de si se incluye una barra inclinada final en la ruta Si desea resultados confiables, debe usar el os.path.joinmétodo en la respuesta anterior.
Artfunkel
21
Dado que esto es aparentemente lo suficientemente complicado como para justificar una pregunta de StackOverflow, creo que esto debería agregarse a la biblioteca os.path como una función incorporada.
antred
324

Utilizando os.path.dirname:

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

Advertencia: os.path.dirname()da resultados diferentes dependiendo de si se incluye una barra inclinada final en la ruta. Esta puede o no ser la semántica que desea. Cf. La respuesta de @ kender usando os.path.join(yourpath, os.pardir).

Wai Yip Tung
fuente
66
os.path.dirname(r'C:\Program Files')¿Qué? Python te está dando el directorio donde estaría el archivo 'Archivos de programa'. Además, ni siquiera tiene que existir, he aquí: os.path.dirname(r'c:\i\like\to\eat\pie')salidas'c:\\i\\like\\to\\eat'
Nick T
41
El póster original no indica que el directorio debe existir. Hay muchos métodos de nombre de ruta que no hacen más que manipular cadenas. Para verificar si el nombre de ruta realmente existe, se requiere un acceso al disco. Depende de la aplicación, esto puede o no ser deseable.
Wai Yip Tung
10
Esta solución es sensible al os.sep final. Diga os.sep == '/'. dirname (foo / bar) -> foo, pero dirname (foo / bar /) -> foo / bar
marcin
66
Eso es por diseño. Se reduce a la interpretación de un camino con un final /. ¿Considera que "ruta1" es igual a "ruta1 /"? La biblioteca usa la interpretación más general de que son distintos. En algún contexto, la gente puede querer tratarlos como equivalentes. En este caso, puede hacer un rstrip ('/') primero. Si la biblioteca escogiera la otra interpretación, perderá fidelidad.
Wai Yip Tung
3
@ Ryan, no sé sobre eso. Hay un RFC 1808 completo escrito para abordar el problema de la ruta relativa en URI y toda la sutileza de la presencia y ausencia de un /. Si conoce alguna documentación que indique que deben tratarse de manera equivalente en general, indíquelo.
Wai Yip Tung
112

El método Pathlib (Python 3.4+)

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

El método tradicional

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


¿Qué método debo usar?

Use el método tradicional si:

  • Le preocupa que el código existente genere errores si fuera a usar un objeto Pathlib. (Dado que los objetos Pathlib no se pueden concatenar con cadenas).

  • Su versión de Python es inferior a 3.4.

  • Necesita una cadena y recibió una cadena. Supongamos, por ejemplo, que tiene una cadena que representa una ruta de archivo y desea obtener el directorio principal para poder colocarlo en una cadena JSON. Sería una tontería convertirlo en un objeto Pathlib y volver de nuevo para eso.

Si no se aplica ninguno de los anteriores, use Pathlib.



¿Qué es pathlib?

Si no sabe qué es Pathlib, el módulo Pathlib es un módulo excelente que hace que trabajar con archivos sea aún más fácil para usted. La mayoría, si no todos los módulos integrados de Python que funcionan con archivos aceptarán tanto objetos como cadenas de Pathlib. He destacado a continuación un par de ejemplos de la documentación de Pathlib que muestran algunas de las cosas interesantes que puedes hacer con Pathlib.

Navegando dentro de un árbol de directorios:

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

Consultar propiedades de ruta:

>>> q.exists()
True
>>> q.is_dir()
False
wp-overwatch.com
fuente
44
Esta es la única respuesta sensata. Si se ve obligado a usar Python 2, solo pip install pathlib2use el backport.
Navin
1
¡Esta solución NO es sensible al arrastre os.sep!
Dylan F
35
import os
p = os.path.abspath('..')

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

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

ivo
fuente
77
Esto solo obtiene el padre de la CWD, no el padre de una ruta arbitraria como lo solicitó el OP.
Sergio
Agregue los puntos dobles al final de su URL y funcionará. Ej. os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') Resultado:E:\\O3M_Tests_Embedded\\branches
Arindam Roychowdhury
Esto significa: /.
loretoparisi
26

Una solución alternativa de @kender

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

¿Dónde yourpathestá la ruta para la que desea el padre?

Pero esta solución no es perfecta, ya que no manejará el caso de yourpathuna cadena vacía o un punto.

Esta otra solución manejará mejor este caso de esquina:

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

Aquí las salidas para cada caso que puede encontrar (la ruta de entrada es relativa):

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

La ruta de entrada es absoluta (ruta de 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
fuente
Normalizar el camino siempre es una buena práctica, especialmente cuando se realiza trabajo multiplataforma.
DevPlayer
¡Esta es la respuesta correcta! Mantiene caminos relativos relativos. ¡Gracias!
Maxim
@Maxim Esta solución no era perfecta, la mejoré ya que la solución original no maneja un caso
benjarobin
@benjarobin Sí, no había pensado en el caso de la esquina. Gracias.
Maxim
18
os.path.split(os.path.abspath(mydir))[0]
Dan Menes
fuente
Esto no funcionará para rutas que están a un directorio, solo devolverá el directorio nuevamente.
Anthony Briggs
2
@AnthonyBriggs, acabo de probar esto usando Python 2.7.3 en Ubuntu 12.04 y parece funcionar bien. os.path.split(os.path.abspath("this/is/a/dir/"))[0]vuelve '/home/daniel/this/is/a'como se esperaba. Por el momento no tengo un cuadro de Windows en ejecución para verificar allí. ¿En qué configuración ha observado el comportamiento que informa?
Dan Menes
Usted podría hacer parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]. Esto, estoy seguro, funciona porque si hay una barra al final, entonces se elimina; si no hay una barra oblicua, esto seguirá funcionando (incluso si la última parte de la ruta tiene solo un carácter largo) debido a la barra oblicua anterior. Por supuesto, esto supone que la ruta es correcta y no dice algo así /a//b/c///d////(en Unix, esto todavía es válido), que en la mayoría de los casos son (adecuados) especialmente cuando haces algo como os.path.abspatho cualquier otra os.pathfunción.
dylnmc
Además, para contrarrestar muchas barras al final, puede escribir un pequeño bucle for que las elimine. Estoy seguro de que incluso podría haber una sola línea inteligente para hacerlo, o tal vez hacer eso y os.path.split en una línea.
dylnmc
@ Den Menes Acabo de verte comentar. No funciona si tiene algo como os.path.split("a/b//c/d///")y, por ejemplo, cd //////dev////// is equivalent to cd / dev / `o cd /dev; Todos estos son válidos en Linux. Acabo de llegar con esto y puede ser útil, sin embargo: os.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]. (Esto esencialmente busca la última no barra y obtiene la subcadena de la ruta hasta ese carácter). Usé path = "/a//b///c///d////"y luego ejecuté la declaración antes mencionada y obtuve '/a//b///c'.
dylnmc
14
os.path.abspath(os.path.join(somepath, '..'))

Observar:

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
fuente
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 "------------------------------------------------------------"
Abuelo
fuente
6

Si solo desea el nombre de la carpeta que es el elemento primario inmediato del archivo proporcionado como argumento y no la ruta absoluta a ese archivo:

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

es decir, con un currentDir valor de/home/user/path/to/myfile/file.ext

El comando anterior devolverá:

myfile

8bitjunkie
fuente
3
os.path.basename (os.path.dirname (current_dir)) también funciona aquí.
DevPlayer
4
>>> import os
>>> os.path.basename(os.path.dirname(<your_path>))

Por ejemplo en Ubuntu:

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

Por ejemplo en Windows:

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

Ambos ejemplos intentaron en Python 2.7

Soumendra
fuente
3
import os.path

os.path.abspath(os.pardir)
Washington Botelho
fuente
Esto supone que desea el directorio principal del "directorio de trabajo actual" y no el directorio principal ninguna ruta en general.
DevPlayer
3

Supongamos que tenemos una estructura de directorios como

1]

/home/User/P/Q/R

Queremos acceder a la ruta de "P" desde el directorio R y luego podemos acceder usando

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

2]

/home/User/P/Q/R

Queremos acceder a la ruta del directorio "Q" desde el directorio R, entonces podemos acceder usando

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

Simplemente agregue algo a la respuesta de Tung (debe usar rstrip('/')para ser más seguro si está en una caja de Unix).

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

Pero, si no usa rstrip('/'), dada su entrada es

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

saldría,

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

que probablemente no es lo que estás viendo, ya que quieres ambas cosas "../data/replies/"y "../data/replies"comportarte de la misma manera.

samsamara
fuente
1
Recomendaría no usar "input" como variable / referencia. Es una función incorporada.
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
fuente
1
print os.path.abspath(os.path.join(os.getcwd(), os.path.pardir))

Puede usar esto para obtener el directorio principal de la ubicación actual de su archivo py.

Eros Nikolli
fuente
2
Esa sugerencia a menudo conduce a errores. os.getcwd () a menudo NO está donde está "su archivo py". Piensa en paquetes. Si "importo algún paquete_con_subpackages", muchos módulos no estarán en el directorio superior de ese paquete. os.getcwd () devuelve donde ejecutas el script superior. Y eso también supone que lo estás haciendo desde una línea de comandos.
DevPlayer
0

OBTENGA la ruta del directorio principal y cree un nuevo directorio (nombre new_dir)

Obtener ruta del directorio principal

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

Ejemplo 1

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

Ejemplo 2

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

>>> 'D:\Dir1'

Entonces una ..ayuda

Arindam Roychowdhury
fuente
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
fuente
0

Las respuestas dadas anteriormente están perfectamente bien para subir uno o dos niveles de directorio, pero pueden ser un poco engorrosos si uno necesita atravesar el árbol de directorios en muchos niveles (por ejemplo, 5 o 10). Esto se puede hacer de manera concisa uniéndose a una lista deN os.pardir s en os.path.join. Ejemplo:

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
fuente