Как мне получить родительский каталог в 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:\\'
>>>

Предостережение: os.path.dirname()дает разные результаты в зависимости от того, включен ли концевой слеш в путь. Это может или не может быть семантика вы хотите. Ср @ ответ Кендера с помощью os.path.join(yourpath, os.pardir).

Вай Ип Тунг
источник
6
os.path.dirname(r'C:\Program Files')что? Python просто дает вам каталог, в котором находится файл Program Files. Более того, он даже не должен существовать, вот: os.path.dirname(r'c:\i\like\to\eat\pie')результаты'c:\\i\\like\\to\\eat'
Ник Т
41
На оригинальном постере не указано, что каталог должен существовать. Есть много методов pathname, которые не делают ничего, кроме манипуляции со строками. Чтобы проверить, действительно ли путь существует, требуется доступ к диску. В зависимости от приложения это может или не может быть желательным.
Вай Ип Тунг
10
это решение чувствительно к конечному os.sep. Скажите os.sep == '/'. dirname (foo / bar) -> foo, но dirname (foo / bar /) -> foo / bar
marcin
6
Это по замыслу. Все сводится к интерпретации пути с висячим /. Считаете ли вы "путь1" равным "путь1 /"? Библиотека использует наиболее общую интерпретацию, что они различны. В некоторых случаях люди могут относиться к ним как к эквиваленту. В этом случае вы можете сначала сделать полоску ('/'). Если библиотека выберет другую интерпретацию, вы потеряете верность.
Вай Ип Тунг
3
@ Райан, я не знаю об этом. Существует целый 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, модуль 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
wp-overwatch.com
источник
4
Это единственный вменяемый ответ. Если вы вынуждены использовать Python 2, просто pip install pathlib2используйте бэкпорт.
Навин
1
Это решение НЕ чувствительно к трейлингу os.sep!
Дилан Ф.
35
import os
p = os.path.abspath('..')

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

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

Иво
источник
7
Это только получает родителя CWD, а не родителя произвольного пути, как запросил OP.
Серхио
Добавьте двойные точки в конце вашего URL, и он будет работать. Например os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') : Результат:E:\\O3M_Tests_Embedded\\branches
Ариндам Ройховдхери
Это означает , что : /.
Лоретопариси
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))     => '/'
benjarobin
источник
Нормализация пути - это всегда хорошая практика, особенно при выполнении кроссплатформенной работы.
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'как и ожидалось. На данный момент у меня нет работающей коробки с Windows, чтобы проверить там. На какой установке вы наблюдали поведение, о котором вы сообщаете?
Дэн Менес
Вы могли бы сделать parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]. Это - я уверен - работает, потому что если на конце есть косая черта, то она удаляется; если косой черты нет, это все равно будет работать (даже если последняя часть пути имеет длину только один символ) из-за предшествующей косой черты. Это, конечно, предполагает, что путь правильный и не говорит что-то вроде /a//b/c///d////(в unix это все еще верно), что в большинстве случаев (правильно), особенно когда вы выполняете что-то подобное os.path.abspathили любую другую os.pathфункцию.
dylnmc
Кроме того, чтобы противостоять множеству слешей в конце, вы можете просто написать небольшой цикл for, который удаляет их. Я уверен, что может быть даже умный однострочный, чтобы сделать это, или, возможно, сделать это и os.path.split в одну строку.
dylnmc
@ Ден Менес Я только что видел, как ты комментируешь. Это не работает, если у вас есть что-то вроде os.path.split("a/b//c/d///")и, например, cd //////dev////// is equivalent to cd / dev / `or 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

8bitjunkie
источник
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

Soumendra
источник
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"вести себя одинаково.

samsamara
источник
1
Я бы порекомендовал не использовать «вход» в качестве переменной / ссылки. Это встроенная функция.
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))
Мигель Мота
источник
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
os.path.abspath('D:\Dir1\Dir2\..')

>>> 'D:\Dir1'

Так ..помогает

Ариндам Ройчоудхури
источник
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
источник
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))
MPA
источник