Jak uzyskać lokalizację katalogu nadrzędnego

134

ten kod to szablony / blog1 / page.html w b.py:

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

ale chcę uzyskać lokalizację katalogu nadrzędnego:

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

i jak uzyskać lokalizację macierzystą

dzięki

zaktualizowane:

to prawda:

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

lub

path = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
zjm1126
źródło
2
Więc chcesz dostać blog1lub a? A gdzie znajduje się twój aktualny plik?
Felix Kling
czy rozumiesz, co robi Twój kod?
SilentGhost
1
tak, pobierz szablony / blog1 / page.html
zjm1126
os.path.join('templates', 'blog1/page.html')wygląda dla mnie dziwnie. Mieszasz rzeczy. Albo os.path.join('templates', 'blog1', 'page.html')albo 'templates/blog1/page.html'. I znacznie łatwiej byłoby os.path.abspath(os.path.join('templates', 'blog1', 'page.html'))wtedy
Felix Kling
1
@zjm: nie, nie dostajesz tej strony. To nie jest czarna skrzynka, której możesz po prostu użyć do pobrania pliku szablonu. Wykonuje serię trywialnych małych kroków i gdybyś mógł je zrozumieć, nie miałbyś tego pytania.
SilentGhost

Odpowiedzi:

181

Można zastosować dirname wielokrotnie wspinać się wyżej: dirname(dirname(file)). Może to jednak dotyczyć tylko pakietu głównego. Jeśli jest to problem, należy os.path.abspath: dirname(dirname(abspath(file))).

Marcelo Cantos
źródło
37
Wiem, że OP wie o dirname. Nie dla wszystkich jest oczywiste, że zastosowanie dirname do katalogu daje katalog nadrzędny.
Marcelo Cantos
4
dirnamenie nie zawsze powrócić do katalogu nadrzędnego; twitter.com/#!/ActiveState/status/671049326788608
Sridhar Ratnakumar
2
@Sridhar: To zależy od twojej perspektywy; Uważam, że ścieżka kończąca się na /nie reprezentuje samej pozycji katalogu-liścia, ale jej zawartość, dlatego np. mv xxx yyy/Zawodzi, jeśli yyynie jest wcześniej istniejącym katalogiem. W każdym razie, nawet jeśli przyjmiemy twój punkt widzenia jako dany, nie ma to znaczenia w kontekście mojej odpowiedzi. Ani filewynik dirnamenigdy nie zakończy się w a /.
Marcelo Cantos
1
Niewielka korekta: dirnamemoże powrócić '/', co wyraźnie kończy się na a /. To jedyny wyjątek, AFAIK.
Marcelo Cantos
56

os.path.abspathniczego nie weryfikuje, więc jeśli już dołączamy ciągi znaków, __file__nie ma potrzeby zawracać sobie głowy dirnameprzyłączaniem się lub tym podobnym. Po prostu potraktuj __file__jako katalog i zacznij się wspinać:

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

To znacznie mniej zawiłe niż os.path.abspath(os.path.join(os.path.dirname(__file__),".."))i mniej więcej tak łatwe do opanowania jak dirname(dirname(__file__)). Wspinanie się na więcej niż dwa poziomy zaczyna być śmieszne.

Ale ponieważ wiemy, ile poziomów trzeba się wspiąć, możemy to uporządkować za pomocą prostej małej funkcji:

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
źródło
2
To fajne, ale byłoby też fajnie, gdyby standardowa biblioteka dodała wygodną funkcję, która to osiągnęła ... nie chcę przychodzić do SO za każdym razem, gdy potrzebuję tej funkcji
gradi3nt
4
Byłby os.path.abspath(os.path.join(__file__, "..", "..")bardziej przenośny?
slowD
45

Użyj ścieżki względnej z pathlibmodułem w Pythonie 3.4+:

from pathlib import Path

Path(__file__).parent

Możesz użyć wielu wywołań, parentaby przejść dalej na ścieżce:

Path(__file__).parent.parent

Jako alternatywę dla określenia parentpodwójnego możesz użyć:

Path(__file__).parents[1]
Gavriel Cohen
źródło
2
Jeśli potrzebujesz ścieżki jako ciągu, ponieważ chcesz ją zmodyfikować, możesz po prostu użyć str(Path(__file__).parent).
Filip
12
os.path.dirname(os.path.abspath(__file__))

Powinien dać ci ścieżkę do a.

Ale jeśli b.pyjest to plik, który jest aktualnie wykonywany, możesz osiągnąć to samo, robiąc to

os.path.abspath(os.path.join('templates', 'blog1', 'page.html'))
Felix Kling
źródło
1
o, wiem, masz rację i chcę uzyskać folder nadrzędny a. jak to zdobyć
zjm1126
@ zjm1126: Zobacz odpowiedź Marcelo Cantos. Zastosuj dirname()dwukrotnie. Wszystko, czego teraz potrzebujesz, powinno znajdować się na tej stronie.
Felix Kling
9

os.pardirto lepszy sposób ../i bardziej czytelny.

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

To zwróci ścieżkę nadrzędną podanej ścieżki

Sun Liwen
źródło
5

Prostym sposobem może być:

import os
current_dir =  os.path.abspath(os.path.dirname(__file__))
parent_dir = os.path.abspath(current_dir + "/../")
print parent_dir
Muneeb Ali
źródło
3

Można dołączyć do dwóch ..folderów, aby uzyskać nadrzędny folder nadrzędny?

path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),"..",".."))
TY
źródło
3

Użyj następujących, aby przejść do poprzedniego folderu:

os.chdir(os.pardir)

Jeśli potrzebujesz wielu skoków, dobrym i łatwym rozwiązaniem będzie w tym przypadku użycie prostego dekoratora.

Marco smdm
źródło
1

Oto kolejne stosunkowo proste rozwiązanie, które:

  • nie używa dirname()(co nie działa zgodnie z oczekiwaniami z argumentami jednego poziomu, takimi jak „plik.txt” lub rodzicami względnymi, takimi jak „..”)
  • nie używa abspath()(unikając jakichkolwiek założeń dotyczących bieżącego katalogu roboczego), ale zamiast tego zachowuje względny charakter ścieżek

po prostu używa normpathi 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)

Wynik:

.
foo/bar
with/trailing
dir
..
/abs
Stefaan
źródło
0

Myślę, że użycie tego jest lepsze:

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
źródło
Niezupełnie, zależy od systemu operacyjnego (nie będzie działać w systemie Windows). Nie pozwala również na użycie ścieżek względnych.
kgadek
To okropne rozwiązanie. Nie będzie działać dla wszystkich systemów operacyjnych
web.learner
0

Próbowałem:

import os
os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))), os.pardir))
gogasca
źródło