Як отримати батьківський каталог в Python?


350

Може хтось скаже мені, як отримати батьківський каталог шляху в Python крос-платформним способом. Напр

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

і

C:\ ---> C:\

Якщо в каталозі немає батьківського каталогу, він повертає сам каталог. Питання може здатися простим, але я не міг його розкопати через Google.

Відповіді:


481

Оновлення з Python 3.4

Використовуйте pathlibмодуль.

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

Стара відповідь

Спробуйте це:

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

де yourpathшлях, який ви хочете для батьків.


137
Ваша відповідь правильна, але суперечлива; os.path.dirnameце функція для цього, начебто a+=5-4більш звикла, ніж a+=1. Питання запитувало лише батьківський каталог, не існує чи справжній батьківський каталог, припускаючи, що символічні посилання заважають.
tzot

16
Це os.pardir, ні os.path.pardir.
bouteillebleu

9
@bouteillebleu: І те, os.pardirі os.path.pardirсправді правильно (вони однакові).
Ерік О Лебігот

45
@tzot: на жаль, os.path.dirnameдає різні результати залежно від того, чи включена в коріння слідова косої риски. Якщо ви хочете отримати достовірні результати, вам потрібно скористатися os.path.joinметодом у відповіді вище.
Artfunkel

21
Оскільки це, мабуть, досить складно для вирішення питання StackOverflow, я вважаю, що це слід додати до бібліотеки os.path як вбудовану функцію.
antred

324

Використання os.path.dirname:

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

Caveat: os.path.dirname()дає різні результати, залежно від того, чи включена косою косою косою доріжкою. Це може бути, а може і не бути семантикою, яку ви хочете. Ср. @ knder відповідь, використовуючи os.path.join(yourpath, os.pardir).


6
os.path.dirname(r'C:\Program Files')що? Python просто надає вам каталог, де буде файл "Файли програм". Більше того, воно навіть не повинно існувати, ось: os.path.dirname(r'c:\i\like\to\eat\pie')вихід'c:\\i\\like\\to\\eat'
Нік Т

41
У початковому плакаті не вказано, що каталог повинен існувати. Існує дуже багато методів імені шляху, який не робить нічого, крім маніпуляції з рядками. Щоб перевірити, чи дійсно існує ім'я шляху, потрібен диск. Залежно від програми це може бути або не бажано.
Вай Іп Тунг

10
це рішення чутливе до останнього os.sep. Скажіть os.sep == '/'. dirname (foo / bar) -> foo, але dirname (foo / bar /) -> foo / bar
marcin

6
Це за дизайном. Це зводиться до інтерпретації шляху із заднім числом /. Ви вважаєте, що "path1" дорівнює "path1 /"? Бібліотека використовує найбільш загальну інтерпретацію, яку вони відрізняють. У деяких умовах люди можуть захотіти трактувати їх як рівнозначні. У цьому випадку ви можете зробити rstrip ('/') спочатку. Якби бібліотека обрала іншу інтерпретацію, ви втратили вірність.
Вай Іп Тунг

3
@Ryan, я не знаю про це. Існує цілий RFC 1808, написаний для вирішення питання щодо відносного шляху в URI та всієї тонкості наявності та відсутності затримки /. Якщо ви знаєте будь-яку документацію, яка говорить про те, що до них слід ставитись рівнозначно, будь ласка, вкажіть це.
Вай Іп Тунг

112

Метод Pathlib (Python 3.4+)

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

Традиційний метод

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


Який метод я повинен використовувати?

Використовуйте традиційний метод, якщо:

  • Ви стурбовані наявними помилками генерування коду, якби він використовував об'єкт Pathlib. (Оскільки об'єкти Pathlib не можуть бути об'єднані рядками.)

  • Ваша версія Python менше 3,4.

  • Вам потрібна рядок, і ви отримали рядок. Скажімо, наприклад, у вас є рядок, що представляє шлях файлу, і ви хочете отримати батьківський каталог, щоб ви могли помістити його в рядок JSON. Було б нерозумно перетворитись на об'єкт Pathlib і знову для цього.

Якщо нічого з перерахованого вище не застосовується, використовуйте Pathlib.



Що таке Патліб?

Якщо ви не знаєте, що таке Pathlib, модуль Pathlib - це надзвичайний модуль, який робить роботу з файлами ще простішою для вас. Більшість, якщо не всі вбудовані модулі Python, які працюють з файлами, приймуть і об'єкти, і рядки Pathlib. Нижче я виділив кілька прикладів із документації Pathlib, які демонструють деякі акуратні речі, які ви можете зробити з Pathlib.

Навігація всередині дерева каталогів:

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

Властивості шляху запиту:

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

4
Це єдина розумна відповідь. Якщо ви змушені використовувати Python 2, просто pip install pathlib2і скористайтесь резервним портфоліо.
Навін

1
Це рішення НЕ чутливий до слідів os.sep!
Ділан Ф

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

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

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


7
Це отримує лише батько CWD, а не батьків довільного шляху, як запитував ОП.
Серхіо

Додайте подвійні крапки в кінці своєї URL-адреси, і це спрацює. Напр. os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') Результат:E:\\O3M_Tests_Embedded\\branches
Аріндам Ройховдхурі

Це означає , що : /.
loretoparisi

26

Альтернативне рішення @kender

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

де yourpathшлях, який ви хочете для батьків.

Але це рішення не є ідеальним, оскільки воно не буде обробляти випадок, коли yourpathпорожня рядок або крапка.

Це інше рішення буде чудово справлятися з цим кутовим корпусом:

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

Ось результати для кожного випадку, який можна знайти (шлях введення відносний):

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

Шлях введення абсолютний (шлях 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))     => '/'

Нормалізація шляху завжди є хорошою практикою, особливо при роботі між платформами.
DevPlayer

Це правильна відповідь! Він підтримує відносні шляхи відносними. Дякую!
Максим

@Maxim Це рішення було не ідеальним, я його вдосконалив, оскільки в початковому рішенні немає жодної справи
Бенджаробін

@benjarobin Так, я не думав про кутовий випадок. Дякую.
Максим

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

Це не працюватиме для шляхів, які знаходяться до каталогу, він просто поверне каталог знову.
Ентоні Бріггс

2
@AnthonyBriggs, я щойно спробував це за допомогою Python 2.7.3 на Ubuntu 12.04, і, здається, він працює добре. os.path.split(os.path.abspath("this/is/a/dir/"))[0]повертається '/home/daniel/this/is/a'як очікувалося. На даний момент у мене немає запущеного вікна для перевірки. Про які налаштування ви спостерігали за поведінкою, про яку ви повідомляєте?
Дан Менес

Ви могли б зробити parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]. Це - я впевнений - працює, тому що якщо на кінці є коса риса, вона знімається; якщо косою косою рисою відсутня, це все одно спрацює (навіть якщо остання частина шляху триває лише один знак) через попередню косу рису. Звичайно, це передбачає, що шлях є правильним, а не говорити щось подібне /a//b/c///d////(в unix це все ще справедливо), що в більшості випадків вони є (належними), особливо коли ви виконуєте щось подібне os.path.abspathчи будь-яку іншу os.pathфункцію.
dylnmc

Крім того, щоб протидіяти великій кількості косої риси в кінці, ви можете просто написати невеликий цикл для циклу, який видаляє їх. Я впевнений, що навіть для цього може бути розумний однокласник, а може це зробити і os.path.split в одному рядку.
dylnmc

@Den Menes Я щойно бачив, як ти коментуєш. Це не працює, якщо у вас є щось на кшталт os.path.split("a/b//c/d///")і, наприклад, cd //////dev////// is equivalent to cd / dev / `або cd /dev; всі вони дійсні в Linux. Я просто придумав це , і це може бути корисно, хоча: os.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]. (Це, по суті, шукає останній несущий косий рядок, і отримує підрядку шляху до цього знака.) Я використав, path = "/a//b///c///d////"а потім запустив вищезгадане твердження і отримав '/a//b///c'.
dylnmc

14
os.path.abspath(os.path.join(somepath, '..'))

Дотримуйтесь:

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

Якщо ви хочете тільки на ім'я папки , яка є безпосереднім батьком наданого файлу в якості аргументу і НЕ на абсолютному шляху до цього файлу:

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

тобто зі currentDirзначенням/home/user/path/to/myfile/file.ext

Наведена вище команда поверне:

myfile


3
os.path.basename (os.path.dirname (current_dir)) також працює тут.
DevPlayer

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

Наприклад в Ubuntu:

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

Наприклад, у Windows:

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

Обидва приклади спробували в Python 2.7


3
import os.path

os.path.abspath(os.pardir)

Це передбачає, що ви хочете, щоб батьківський каталог "поточного робочого каталогу", а не батьківський каталог будь-який шлях в цілому.
DevPlayer

3

Припустимо, у нас така структура каталогів

1]

/home/User/P/Q/R

Ми хочемо отримати доступ до шляху "P" з каталогу R, тоді ми можемо отримати доступ за допомогою

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

2]

/home/User/P/Q/R

Ми хочемо отримати доступ до шляху каталогу "Q" з каталогу R, тоді ми можемо отримати доступ за допомогою

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

2

Просто додайте щось у відповідь Тунга (вам потрібно скористатися rstrip('/')більш безпечною стороною, якщо ви знаходитесь в коробці Unix).

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

Але, якщо ви не користуєтесь rstrip('/'), враховуючи, що ваш внесок є

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

виведе,

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

що, мабуть, не те, на що ти дивишся так, як хочеш обох "../data/replies/"і "../data/replies"поводитись однаково.


1
Я б рекомендував не використовувати "input" як змінну / посилання. Це вбудована функція.
DevPlayer


1
print os.path.abspath(os.path.join(os.getcwd(), os.path.pardir))

Ви можете використовувати це, щоб отримати батьківський каталог поточного розташування вашого файлу py.


2
Ця пропозиція часто призводить до помилок. os.getcwd () часто НЕ там, де "ваш файл py". Подумайте про пакети. Якщо я "імпортую some_package_with_subpackages", багато модулів не будуть в найпопулярнішому каталозі цього пакета. os.getcwd () повертається там, де ви виконуєте найкращий сценарій. І це також передбачає, що ви робите це з командного рядка.
DevPlayer

0

Отримати шлях батьківського каталогу та створити новий каталог (ім'я new_dir)

Отримати шлях батьківського каталогу

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

Приклад 1

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

Приклад 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

Наведені вище відповіді цілком чудові для підняття одного або двох рівнів каталогів, але вони можуть стати трохи громіздкими, якщо потрібно пройти дерево каталогів на багато рівнів (скажімо, 5 або 10). Це можна зробити стисло, приєднавшись до списку N os.pardirs os.path.join. Приклад:

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))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.