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.

Mridang Agarwalla
fonte

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.

kender
fonte
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).

Wai Yip Tung
fonte
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
wp-overwatch.com
fonte
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:\\\

ivo
fonte
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))     => '/'
benjarobin
fonte
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]
Dan Menes
fonte
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', '..'))
Ignacio Vazquez-Abrams
fonte
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 "------------------------------------------------------------"
Avô
fonte
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

8bitjunkie
fonte
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

Soumendra
fonte
3
import os.path

os.path.abspath(os.pardir)
Washington Botelho
fonte
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));
Rakesh Chaudhari
fonte
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.

samsamara
fonte
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))
Miguel Mota
fonte
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.

Eros Nikolli
fonte
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'))
Jay Patel
fonte
0
os.path.abspath('D:\Dir1\Dir2\..')

>>> 'D:\Dir1'

Então ..ajuda

Arindam Roychowdhury
fonte
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
fonte
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))
MPA
fonte