Como obter o local do diretório pai

129

este código é obter os templates / blog1 / page.html em b.py:

path = os.path.join(os.path.dirname(__file__), os.path.join('templates', 'blog1/page.html'))

mas eu quero obter a localização do diretório pai:

aParent
   |--a
   |  |---b.py
   |      |---templates
   |              |--------blog1
   |                         |-------page.html
   |--templates
          |--------blog1
                     |-------page.html

e como obter a localização aParent

obrigado

Atualizada:

isto está certo:

dirname=os.path.dirname
path = os.path.join(dirname(dirname(__file__)), os.path.join('templates', 'blog1/page.html'))

ou

path = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
zjm1126
fonte
2
Então você quer obter blog1ou a? E onde está localizado o seu arquivo atual?
Felix Kling
você entende o que seu código está fazendo?
SilentGhost
1
sim, obter os modelos / blog1 / page.html
zjm1126
os.path.join('templates', 'blog1/page.html')parece estranho para mim. Você está misturando as coisas. Ou os.path.join('templates', 'blog1', 'page.html')ou 'templates/blog1/page.html'. E muito mais fácil seria os.path.abspath(os.path.join('templates', 'blog1', 'page.html'))então
Felix Kling
1
@ zjm: não, você não consegue essa página. Não é uma caixa preta que você pode usar para obter o arquivo de modelo. Ele executa uma série de pequenos passos triviais e, se você pudesse entendê-los, não teria essa pergunta.
SilentGhost

Respostas:

171

Você pode aplicar dirname repetidamente para subir mais alto: dirname(dirname(file)). No entanto, isso só pode ir até o pacote raiz. Se este é um problema, use os.path.abspath: dirname(dirname(abspath(file))).

Marcelo Cantos
fonte
37
Eu sei que o OP conhece dirname. Não é óbvio para todos que a aplicação de dirname a um diretório produz o diretório pai.
Marcelo Cantos
4
dirnamese não sempre retornar o diretório pai; Twitter.com/#!/ActiveState/status/671049326788608
Sridhar Ratnakumar
2
@Sridhar: Isso depende da sua perspectiva; Considero um caminho que termina /como não representando a própria entrada do diretório folha, mas seu conteúdo, e é por isso que, por exemplo, mv xxx yyy/falha se yyynão for um diretório preexistente. De qualquer forma, mesmo se considerarmos o seu argumento como um dado, é irrelevante no contexto da minha resposta. Nem fileo resultado de dirnamejamais terminará em a /.
Marcelo Cantos
1
Correção menor: dirnamepode retornar '/', o que claramente termina em a /. Essa é a única exceção, AFAIK.
Marcelo Cantos
55

os.path.abspathnão valida nada, por isso, se já estamos anexando cadeias de caracteres, __file__não há necessidade de se preocupar com a dirnamejunção ou nada disso. Apenas trate __file__como um diretório e comece a subir:

# climb to __file__'s parent's parent:
os.path.abspath(__file__ + "/../../")

Isso é muito menos complicado do que os.path.abspath(os.path.join(os.path.dirname(__file__),".."))e tão gerenciável quanto dirname(dirname(__file__)). Subir mais de dois níveis começa a ficar ridículo.

Mas, como sabemos quantos níveis subir, poderíamos limpar isso com uma pequena função simples:

uppath = lambda _path, n: os.sep.join(_path.split(os.sep)[:-n])

# __file__ = "/aParent/templates/blog1/page.html"
>>> uppath(__file__, 1)
'/aParent/templates/blog1'
>>> uppath(__file__, 2)
'/aParent/templates'
>>> uppath(__file__, 3)
'/aParent'
joemaller
fonte
2
Isso é bom, mas também seria legal se a biblioteca padrão acrescentou uma função de conveniência que conseguiu isso ... não querem vir para SO cada vez que eu preciso disso func
gradi3nt
4
Seria os.path.abspath(os.path.join(__file__, "..", "..")mais portátil?
slowD
40

Use o caminho relativo com o pathlibmódulo no Python 3.4+:

from pathlib import Path

Path(__file__).parent

Você pode usar várias chamadas parentpara ir além no caminho:

Path(__file__).parent.parent

Como alternativa à especificação parentduas vezes, você pode usar:

Path(__file__).parents[1]
Gavriel Cohen
fonte
2
Se você precisar do caminho como uma sequência porque deseja modificá-lo, basta usar str(Path(__file__).parent).
Philipp
12
os.path.dirname(os.path.abspath(__file__))

Deve lhe dar o caminho para a.

Mas se b.pyé o arquivo que está sendo executado no momento, você pode conseguir o mesmo fazendo apenas

os.path.abspath(os.path.join('templates', 'blog1', 'page.html'))
Felix Kling
fonte
1
o, eu sei, você está certo e quero obter a pasta pai do a. como obtê-lo
zjm1126 12/12
@ zjm1126: Veja a resposta de Marcelo Cantos. Aplique dirname()duas vezes. Tudo o que você precisa agora deve estar neste site.
Felix Kling
9

os.pardiré uma maneira melhor ../e mais legível.

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

Isso retornará o caminho pai do determinado_caminho

Sun Liwen
fonte
5

Uma maneira simples pode ser:

import os
current_dir =  os.path.abspath(os.path.dirname(__file__))
parent_dir = os.path.abspath(current_dir + "/../")
print parent_dir
Muneeb Ali
fonte
3

Pode ser juntar duas ..pastas, para obter pai da pasta pai?

path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),"..",".."))
VOCÊS
fonte
3

Use o seguinte para ir para a pasta anterior:

os.chdir(os.pardir)

Se você precisar de vários saltos, uma solução boa e fácil será usar um decorador simples neste caso.

Marco smdm
fonte
1

Aqui está outra solução relativamente simples que:

  • não usa dirname()(o que não funciona como esperado em argumentos de um nível, como "arquivo.txt" ou pais relativos, como "..")
  • não usa abspath()(evitando suposições sobre o diretório de trabalho atual), mas preserva o caráter relativo dos caminhos

apenas usa normpathe join:

def parent(p):
    return os.path.normpath(os.path.join(p, os.path.pardir))

# Example:
for p in ['foo', 'foo/bar/baz', 'with/trailing/slash/', 
        'dir/file.txt', '../up/', '/abs/path']:
    print parent(p)

Resultado:

.
foo/bar
with/trailing
dir
..
/abs
Stefaan
fonte
0

Eu acho que usar isso é melhor:

os.path.realpath(__file__).rsplit('/', X)[0]


In [1]: __file__ = "/aParent/templates/blog1/page.html"

In [2]: os.path.realpath(__file__).rsplit('/', 3)[0]
Out[3]: '/aParent'

In [4]: __file__ = "/aParent/templates/blog1/page.html"

In [5]: os.path.realpath(__file__).rsplit('/', 1)[0]
Out[6]: '/aParent/templates/blog1'

In [7]: os.path.realpath(__file__).rsplit('/', 2)[0]
Out[8]: '/aParent/templates'

In [9]: os.path.realpath(__file__).rsplit('/', 3)[0]
Out[10]: '/aParent'
dongweiming
fonte
Não é bem assim, depende do sistema operacional (não funcionará no Windows). Também não permite usar caminhos relativos.
kgadek
Essa é uma solução terrível. Não funcionará para todos os sistemas operacionais
web.learner 26/07
0

Eu tentei:

import os
os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))), os.pardir))
gogasca
fonte