Como obtenho o diretório pai no Python?


350

Alguém poderia me dizer como obter o diretório pai de um caminho em Python de uma maneira multiplataforma. Por exemplo

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

e

C:\ ---> C:\

Se o diretório não tiver um diretório pai, ele retornará o próprio diretório. A pergunta pode parecer simples, mas não consegui desenterrá-la através do Google.

Respostas:


481

Atualização do Python 3.4

Use o pathlibmódulo

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

Resposta antiga

Tente o seguinte:

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

onde yourpathestá o caminho para o qual você deseja os pais.


136
Sua resposta está correta, mas complicada; os.path.dirnameé a função para isso, como a+=5-4é mais complicado do que a+=1. A pergunta solicitou apenas o diretório pai, não se existe ou o diretório pai verdadeiro , assumindo que os links simbólicos atrapalham.
tzot 24/05

15
É os.pardir, não os.path.pardir.
21712 bouteillebleu

9
@ Bouteillebleu: Ambos os.pardire os.path.pardirestão realmente corretos (são idênticos).
Eric O Lebigot 5/03

45
@ tzot: infelizmente, os.path.dirnamedá resultados diferentes, dependendo se uma barra final está incluída no caminho. Se você deseja resultados confiáveis, use o os.path.joinmétodo na resposta acima.
Artfunkel

21
Como isso é aparentemente complicado o suficiente para justificar uma pergunta do StackOverflow, acho que isso deve ser adicionado à biblioteca os.path como uma função interna.
antred

324

Usando os.path.dirname:

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

Advertência: os.path.dirname()fornece resultados diferentes dependendo da inclusão de uma barra no caminho. Essa pode ou não ser a semântica que você deseja. Cf. @ resposta do kender usando os.path.join(yourpath, os.pardir).


6
os.path.dirname(r'C:\Program Files')que? O Python está apenas fornecendo o diretório onde estaria o arquivo 'Arquivos de Programas'. Além do mais, não tem sequer a existir eis: os.path.dirname(r'c:\i\like\to\eat\pie')saídas'c:\\i\\like\\to\\eat'
Nick T

41
O pôster original não indica que o diretório precisa existir. Existem muitos métodos de nome de caminho que não fazem nada além da manipulação de strings. Para verificar se o nome do caminho realmente existe requer um acesso ao disco. Depende da aplicação, isso pode ou não ser desejável.
Wai Yip Tung

10
Esta solução é sensível ao os.sep à direita. Diga os.sep == '/'. dirname (foo / bar) -> foo, mas dirname (foo / bar /) -> foo / bar
Marcin

6
Isso é por design. Tudo se resume à interpretação de um caminho com um / final. Você considera "caminho1" igual a "caminho1 /"? A biblioteca usa a interpretação mais geral de que são distintas. Em algum contexto, as pessoas podem querer tratá-las como equivalentes. Nesse caso, você pode fazer uma rstrip ('/') primeiro. Se a biblioteca escolhesse a outra interpretação, você perderia a fidelidade.
Wai Yip Tung

3
@ Ryan, eu não sei sobre isso. Existe um RFC 1808 inteiro escrito para resolver a questão do caminho relativo no URI e toda a sutileza da presença e ausência de um / final. Se você conhece alguma documentação que diz que eles devem ser tratados de maneira equivalente em geral, indique-a.
Wai Yip Tung

112

O método Pathlib (Python 3.4 ou superior)

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

O método tradicional

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


Qual método devo usar?

Use o método tradicional se:

  • Você está preocupado com o código existente que gera erros se for usar um objeto Pathlib. (Como os objetos Pathlib não podem ser concatenados com seqüências de caracteres.)

  • Sua versão do Python é menor que 3.4.

  • Você precisa de uma sequência e recebeu uma sequência. Digamos, por exemplo, que você tenha uma sequência representando um caminho de arquivo e deseje obter o diretório pai para poder colocá-lo em uma sequência JSON. Seria meio bobo converter em um objeto Pathlib e voltar novamente para isso.

Se nenhuma das opções acima se aplicar, use Pathlib.



O que é o Pathlib?

Se você não sabe o que é o Pathlib, o módulo Pathlib é um ótimo módulo que facilita ainda mais o trabalho com arquivos. A maioria, se não todos os módulos Python internos que funcionam com arquivos, aceitarão objetos e cadeias de caracteres Pathlib. Eu destaquei abaixo alguns exemplos da documentação do Pathlib que mostram algumas das coisas legais que você pode fazer com o Pathlib.

Navegando dentro de uma árvore de diretórios:

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

Consultando propriedades do caminho:

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

4
Esta é a única resposta sã. Se você for forçado a usar o Python 2, apenas pip install pathlib2use o backport.
Navin

11
Esta solução NÃO é sensível à fuga os.sep!
Dylan F

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

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

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


7
Isso apenas obtém o pai do CWD, não o pai de um caminho arbitrário, conforme solicitado pelo OP.
Sergio

Adicione os pontos duplos no final do seu URL e ele funcionará. os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') Resultado:E:\\O3M_Tests_Embedded\\branches
Arindam Roychowdhury

Isto significa: /.
loretoparisi 26/07/19

26

Uma solução alternativa do @kender

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

onde yourpathestá o caminho para o qual você deseja os pais.

Mas essa solução não é perfeita, pois não trata do caso em que yourpathhá uma string vazia ou um ponto.

Esta outra solução irá lidar mais bem com este caso de canto:

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

Aqui as saídas para todos os casos que podem ser encontrados (o caminho de entrada é 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))    => '../..'

O caminho de entrada é absoluto (caminho do 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))     => '/'

Normalizar o caminho é sempre uma boa prática, especialmente ao realizar trabalhos em várias plataformas.
DevPlayer 28/01

Essa é a resposta correta! Mantém os caminhos relativos relativos. Obrigado!
Maxim

@Maxim Esta solução não era perfeito, eu tinha melhorado, já que a solução original não lidar com um caso
benjarobin

@ benjarobin Sim, eu não tinha pensado na caixa da esquina. Obrigado.
Maxim

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

Isso não funcionará para caminhos que estão em um diretório, apenas retornará o diretório novamente.
Anthony Briggs

2
@ AnthonyBriggs, eu apenas tentei isso usando o Python 2.7.3 no Ubuntu 12.04 e parece funcionar bem. os.path.split(os.path.abspath("this/is/a/dir/"))[0]retorna '/home/daniel/this/is/a'como esperado. No momento, não tenho uma caixa do Windows em execução para verificar lá. Em que configuração você observou o comportamento relatado?
Dan Menes 22/02

Você poderia fazer parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]. Isso - tenho certeza - funciona porque se houver uma barra no final, ela será removida; se não houver barra, isso ainda funcionará (mesmo que a última parte do caminho tenha apenas um caractere) por causa da barra anterior. É claro que isso pressupõe que o caminho é adequado e não diz algo como /a//b/c///d////(no unix isso ainda é válido), que na maioria dos casos são (adequados), especialmente quando você faz algo como os.path.abspathou qualquer outra os.pathfunção.
dylnmc

Além disso, para combater muitas barras no final, você pode escrever um pequeno loop for que as remove. Tenho certeza de que pode haver uma única linha inteligente para fazer isso, ou talvez faça isso e os.path.split em uma linha.
Dllnmc

@ Men Men Acabei de ver você comentar. Não funciona se você tiver algo parecido os.path.split("a/b//c/d///")e, por exemplo, cd //////dev////// is equivalent to cd / dev / `ou cd /dev; tudo isso é válido no linux. Eu só vim com isso e pode ser útil, no entanto: os.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]. (Isso basicamente procura o último não-barra e obtém a substring do caminho até esse caractere.) Eu usei path = "/a//b///c///d////"e, em seguida, executei a declaração acima e obtive '/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', '..'))

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 você deseja que apenas o nome da pasta que é o pai imediato do arquivo seja fornecido como argumento e não o caminho absoluto para esse arquivo:

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

ou seja, com um currentDirvalor de/home/user/path/to/myfile/file.ext

O comando acima retornará:

myfile


3
os.path.basename (os.path.dirname (current_dir)) também funciona aqui.
DevPlayer 28/01

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

Por exemplo no Ubuntu:

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

Por exemplo no Windows:

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

Ambos os exemplos tentados no Python 2.7


3
import os.path

os.path.abspath(os.pardir)

Isso pressupõe que você deseja que o diretório pai "do diretório de trabalho atual" e não o caminho principal em geral.
DevPlayer

3

Suponha que tenhamos uma estrutura de diretórios como

1]

/home/User/P/Q/R

Queremos acessar o caminho de "P" no diretório R, então podemos acessar usando

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

2]

/home/User/P/Q/R

Queremos acessar o caminho do diretório "Q" a partir do diretório R, então podemos acessar usando

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

2

Basta adicionar algo à resposta de Tung (você precisa usar rstrip('/')o lado mais seguro se estiver em uma caixa unix).

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

Mas, se você não usar rstrip('/'), dado que sua entrada é

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

produziria,

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

o que provavelmente não é o que você está vendo, pois deseja os dois "../data/replies/"e "../data/replies"se comporta da mesma maneira.


11
Eu recomendaria não usar "input" como uma variável / referência. É uma função interna.
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))

Você pode usar isso para obter o diretório pai do local atual do seu arquivo py.


2
Essa sugestão geralmente leva a erros. os.getcwd () geralmente NÃO está onde "seu arquivo py" está. Pense em pacotes. Se eu "importar some_package_with_subpackages", muitos módulos não estarão no diretório mais alto desse pacote. os.getcwd () retorna onde você executa o script mais avançado. E isso também pressupõe que você esteja fazendo isso a partir de uma linha de comando.
DevPlayer 28/01

0

GET Caminho do diretório pai e criar novo diretório (nome new_dir)

Obter caminho do diretório pai

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

Exemplo 1

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

Exemplo 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

As respostas dadas acima são perfeitamente adequadas para subir um ou dois níveis de diretório, mas podem ficar um pouco complicadas se for necessário percorrer a árvore de diretórios em muitos níveis (por exemplo, 5 ou 10). Isso pode ser feito de forma concisa, juntando-se a uma lista de N os.pardirs os.path.join. Exemplo:

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))
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.