Bagaimana cara mendapatkan direktori induk dalam Python?

350

Bisakah seseorang memberi tahu saya cara mendapatkan direktori induk dari jalur di Python dengan cara lintas platform. Misalnya

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

dan

C:\ ---> C:\

Jika direktori tidak memiliki direktori induk, ia mengembalikan direktori itu sendiri. Pertanyaannya mungkin tampak sederhana tetapi saya tidak dapat menggali melalui Google.

Mridang Agarwalla
sumber

Jawaban:

481

Perbarui dari Python 3.4

Gunakan pathlibmodul.

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

Jawaban lama

Coba ini:

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

di mana yourpathjalur yang Anda inginkan untuk orang tua.

kender
sumber
137
Jawaban Anda benar tetapi berbelit-belit; os.path.dirnameadalah fungsi untuk ini, suka a+=5-4lebih berbelit daripada a+=1. Pertanyaan yang diminta hanya direktori induk, bukan apakah ada atau direktori induk sebenarnya dengan asumsi tautan simbolik menghalangi
tzot
16
Ini os.pardir, tidak os.path.pardir.
bouteillebleu
9
@bouteillebleu: Keduanya os.pardirdan os.path.pardirsebenarnya benar (keduanya identik).
Eric O Lebigot
45
@tzot: sayangnya os.path.dirnamememberikan hasil yang berbeda tergantung pada apakah garis miring disertakan di jalan. Jika Anda ingin hasil yang dapat diandalkan, Anda perlu menggunakan os.path.joinmetode dalam jawaban di atas.
Artfunkel
21
Karena ini tampaknya cukup rumit untuk menjamin pertanyaan StackOverflow, saya merasa bahwa ini harus ditambahkan ke pustaka os.path sebagai fungsi bawaan.
antred
324

Menggunakan os.path.dirname:

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

Peringatan: os.path.dirname()memberikan hasil yang berbeda tergantung pada apakah garis miring dimasukkan dalam jalur. Ini mungkin atau mungkin bukan semantik yang Anda inginkan. Lih @ jawab kender menggunakan os.path.join(yourpath, os.pardir).

Wai Yip Tung
sumber
6
os.path.dirname(r'C:\Program Files')apa? Python hanya memberi Anda direktori tempat file 'Program Files' berada. Terlebih lagi, bahkan tidak harus ada, lihat: os.path.dirname(r'c:\i\like\to\eat\pie')output'c:\\i\\like\\to\\eat'
Nick T
41
Poster asli tidak menyatakan bahwa direktori harus ada. Ada banyak metode pathname yang melakukan manipulasi string. Untuk memverifikasi apakah pathname benar-benar ada memerlukan akses disk. Tergantung pada aplikasi ini mungkin atau mungkin tidak diinginkan.
Wai Yip Tung
10
solusi ini peka terhadap trailing os.sep. Katakan os.sep == '/'. dirname (foo / bar) -> foo, tetapi dirname (foo / bar /) -> foo / bar
marcin
6
Itu dengan desain. Turun ke interpretasi jalan dengan trailing /. Apakah Anda menganggap "path1" sama dengan "path1 /"? Perpustakaan menggunakan interpretasi paling umum bahwa mereka berbeda. Dalam beberapa konteks orang mungkin ingin memperlakukan mereka sebagai setara. Dalam hal ini Anda dapat melakukan rstrip ('/') terlebih dahulu. Seandainya perpustakaan memilih interpretasi lain Anda akan kehilangan kesetiaan.
Wai Yip Tung
3
@Ryan, saya tidak tahu tentang itu. Ada seluruh RFC 1808 ditulis untuk mengatasi masalah jalur relatif di URI dan semua kehalusan dari ada dan tidak adanya trailing /. Jika Anda mengetahui dokumentasi yang mengatakan bahwa mereka harus diperlakukan setara secara umum, harap tunjukkan.
Wai Yip Tung
112

Metode Pathlib (Python 3.4+)

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

Metode tradisional

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


Metode mana yang harus saya gunakan?

Gunakan metode tradisional jika:

  • Anda khawatir tentang kesalahan pembuatan kode yang ada jika menggunakan objek Pathlib. (Karena objek Pathlib tidak dapat digabungkan dengan string.)

  • Versi Python Anda kurang dari 3,4.

  • Anda membutuhkan string, dan Anda menerima string. Katakan misalnya Anda memiliki string yang mewakili sebuah file tap, dan Anda ingin mendapatkan direktori induk sehingga Anda dapat meletakkannya di string JSON. Akan agak konyol untuk mengkonversi ke objek Pathlib dan kembali lagi untuk itu.

Jika tidak ada yang di atas berlaku, gunakan Pathlib.



Apa itu Pathlib?

Jika Anda tidak tahu apa itu Pathlib, modul Pathlib adalah modul hebat yang membuat bekerja dengan file lebih mudah bagi Anda. Sebagian besar jika tidak semua modul Python bawaan yang berfungsi dengan file akan menerima objek dan string Pathlib. Saya telah menyoroti di bawah ini beberapa contoh dari dokumentasi Pathlib yang menampilkan beberapa hal rapi yang dapat Anda lakukan dengan Pathlib.

Menavigasi di dalam pohon direktori:

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

Properti jalur kueri:

>>> q.exists()
True
>>> q.is_dir()
False
wp-overwatch.com
sumber
4
Ini satu-satunya jawaban yang waras. Jika Anda terpaksa menggunakan Python 2, adil pip install pathlib2dan gunakan backport.
Navin
1
Solusi ini BUKAN peka terhadap trailing os.sep!
Dylan F
35
import os
p = os.path.abspath('..')

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

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

ivo
sumber
7
Ini hanya mendapatkan induk dari CWD, bukan induk dari jalur arbitrer seperti yang diminta OP.
Sergio
Tambahkan titik ganda di akhir URL Anda dan itu akan berfungsi Misalnya os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') Hasil:E:\\O3M_Tests_Embedded\\branches
Arindam Roychowdhury
Ini berarti: /.
loretoparisi
26

Solusi alternatif @kender

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

di mana yourpathjalur yang Anda inginkan untuk orang tua.

Tetapi solusi ini tidak sempurna, karena tidak akan menangani kasus di mana yourpathstring kosong, atau sebuah titik.

Solusi lain ini akan menangani kasus sudut ini dengan lebih baik:

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

Di sini keluaran untuk setiap kasus yang dapat ditemukan (Jalur input relatif):

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

Jalur input mutlak (jalur 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
sumber
Normalisasi jalan selalu merupakan praktik yang baik, terutama saat melakukan pekerjaan lintas platform.
DevPlayer
Ini jawaban yang benar! Itu membuat jalur relatif relatif. Terima kasih!
Maxim
@ Maxim Solusi ini tidak sempurna, saya memperbaikinya karena solusi asli tidak menangani satu kasus
benjarobin
@ Penjaraobin Ya, saya belum memikirkan sudut kasing. Terima kasih.
Maxim
18
os.path.split(os.path.abspath(mydir))[0]
Dan Menes
sumber
Ini tidak akan berfungsi untuk jalur yang menuju ke direktori, itu hanya akan mengembalikan direktori lagi.
Anthony Briggs
2
@AnthonyBriggs, saya baru saja mencoba menggunakan Python 2.7.3 di Ubuntu 12.04 dan sepertinya berfungsi dengan baik. os.path.split(os.path.abspath("this/is/a/dir/"))[0]kembali '/home/daniel/this/is/a'seperti yang diharapkan. Saya tidak memiliki kotak Windows yang sedang berjalan untuk memeriksa di sana. Pada pengaturan apa yang telah Anda amati perilaku yang Anda laporkan?
Dan Menes
Anda bisa melakukannya parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]. Ini - saya yakin - berfungsi karena jika ada garis miring pada ujungnya, maka garis tersebut akan dihapus; jika tidak ada garis miring, ini masih akan berhasil (bahkan jika bagian terakhir dari jalur hanya sepanjang satu karakter) karena garis miring sebelumnya. Ini tentu saja mengasumsikan bahwa path itu benar dan tidak mengatakan sesuatu seperti /a//b/c///d////(dalam unix ini masih valid), yang dalam kebanyakan kasus mereka (benar) terutama ketika Anda melakukan sesuatu seperti os.path.abspathatau os.pathfungsi lainnya .
dylnmc
Juga, untuk menangkal banyak garis miring pada akhirnya, Anda bisa menulis kecil untuk loop yang menghilangkannya. Saya yakin bahkan mungkin ada satu-liner pintar untuk melakukannya, atau mungkin melakukannya dan os.path.split dalam satu baris.
dylnmc
@Den Menes Saya baru saja melihat Anda berkomentar. Tidak berfungsi jika Anda memiliki sesuatu seperti os.path.split("a/b//c/d///")dan, misalnya, cd //////dev////// is equivalent to cd / dev / `atau cd /dev; semua ini berlaku di linux. Aku hanya datang dengan ini dan itu mungkin berguna, meskipun: os.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]. (Ini pada dasarnya mencari non-slash terakhir, dan mendapatkan substring dari path ke char itu.) Saya menggunakan path = "/a//b///c///d////"dan kemudian menjalankan pernyataan tersebut dan mendapatkan '/a//b///c'.
dylnmc
14
os.path.abspath(os.path.join(somepath, '..'))

Mengamati:

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
sumber
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 "------------------------------------------------------------"
Eyang lelaki
sumber
6

Jika Anda ingin hanya satu nama dari folder yang merupakan induk langsung dari file yang disediakan sebagai argumen dan tidak dengan path absolut ke file yang:

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

yaitu dengan currentDirnilai/home/user/path/to/myfile/file.ext

Perintah di atas akan kembali:

myfile

8bitjunkie
sumber
3
os.path.basename (os.path.dirname (current_dir)) juga berfungsi di sini.
DevPlayer
4
>>> import os
>>> os.path.basename(os.path.dirname(<your_path>))

Misalnya di Ubuntu:

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

Misalnya di Windows:

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

Kedua contoh dicoba dengan Python 2.7

Soumendra
sumber
3
import os.path

os.path.abspath(os.pardir)
Washington Botelho
sumber
Ini mengandaikan Anda menginginkan direktori induk "direktori kerja saat ini" dan bukan direktori induk jalur apa pun secara umum.
DevPlayer
3

Misalkan kita memiliki struktur direktori seperti

1]

/home/User/P/Q/R

Kami ingin mengakses jalur "P" dari direktori R maka kami dapat mengakses menggunakan

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

2]

/home/User/P/Q/R

Kami ingin mengakses jalur direktori "Q" dari direktori R maka kami dapat mengakses menggunakan

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

Hanya menambahkan sesuatu ke jawaban Tung (Anda harus menggunakan rstrip('/')untuk menjadi lebih aman jika Anda menggunakan kotak unix).

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

Tetapi, jika Anda tidak menggunakannya rstrip('/'), berikan masukan Anda

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

akan menghasilkan,

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

yang mungkin bukan apa yang Anda lihat karena Anda ingin keduanya "../data/replies/"dan "../data/replies"berperilaku dengan cara yang sama.

samsamara
sumber
1
Saya akan merekomendasikan untuk tidak menggunakan "input" sebagai variabel / referensi. Ini adalah fungsi bawaan.
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
sumber
1
print os.path.abspath(os.path.join(os.getcwd(), os.path.pardir))

Anda dapat menggunakan ini untuk mendapatkan direktori induk dari lokasi saat ini dari file py Anda.

Eros Nikolli
sumber
2
Saran itu seringkali mengarah pada bug. os.getcwd () sering BUKAN di mana "file py Anda" adalah. Pikirkan paket. Jika saya "mengimpor some_package_with_subpackages" banyak modul tidak akan berada di direktori paling atas paket itu. os.getcwd () mengembalikan tempat Anda menjalankan skrip paling atas. Dan itu juga menganggap Anda melakukannya dari baris perintah.
DevPlayer
0

DAPATKAN Path Direktori Induk dan buat Direktori baru (nama new_dir)

Dapatkan Jalur Direktori Induk

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

Contoh 1

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

Contoh 2

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

>>> 'D:\Dir1'

Jadi sangat ..membantu

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

Jawaban yang diberikan di atas semuanya baik-baik saja untuk naik satu atau dua tingkat direktori, tetapi mereka mungkin agak rumit jika seseorang perlu melintasi pohon direktori dengan banyak tingkatan (katakanlah, 5 atau 10). Ini dapat dilakukan secara ringkas dengan bergabung dengan daftar N os.pardirs di os.path.join. Contoh:

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
sumber