os.path.commonprefix () и os.path.relpath () ваши друзья:
>>> print os.path.commonprefix(['/usr/var/log', '/usr/var/security'])
'/usr/var'
>>> print os.path.commonprefix(['/tmp', '/usr/var']) # No common prefix: the root is the common prefix
'/'
Таким образом, вы можете проверить, является ли общий префикс одним из путей, т.е. является ли один из путей общим предком:
paths = […, …, …]
common_prefix = os.path.commonprefix(list_of_paths)
if common_prefix in paths:
…
Затем вы можете найти относительные пути:
relative_paths = [os.path.relpath(path, common_prefix) for path in paths]
С помощью этого метода вы даже можете обрабатывать более двух путей и проверить, все ли пути ниже одного из них.
PS : в зависимости от того, как выглядят ваши пути, вы можете сначала выполнить некоторую нормализацию (это полезно в ситуациях, когда неизвестно, заканчиваются ли они всегда символом «/» или нет, или если некоторые пути являются относительными). Соответствующие функции включают os.path.abspath () и os.path.normpath () .
PPS : как упоминал Питер Бриггс в комментариях, простой подход, описанный выше, может потерпеть неудачу:
>>> os.path.commonprefix(['/usr/var', '/usr/var2/log'])
'/usr/var'
хотя /usr/var
это не общий префикс путей. Принудительное завершение всех путей знаком «/» перед вызовом commonprefix()
решает эту (специфическую) проблему.
PPPS : как упоминалось в bluenote10, добавление косой черты не решает общую проблему. Вот его следующий вопрос: Как обойти ошибку os.path.commonprefix Python?
PPPPS : начиная с Python 3.4, у нас есть pathlib , модуль, который обеспечивает более разумную среду манипулирования путями. Я предполагаю, что общий префикс набора путей может быть получен, получая все префиксы каждого пути (с PurePath.parents()
), беря пересечение всех этих родительских наборов, и выбирая самый длинный общий префикс.
PPPPPS : Python 3.5 представил правильное решение этого вопроса: os.path.commonpath()
возвращает правильный путь.
commonprefix
, например, с общим префиксом for/usr/var/log
и/usr/var2/log
возвращаемым как/usr/var
- что, вероятно, не то, что вы ожидаете. (Также возможно, чтобы он возвращал пути, которые не являются действительными каталогами.)['/usr/var1/log/', '/usr/var2/log/']
?os.path.relpath
:Итак, если относительный путь начинается с
'..'
- это означает, что второй путь не является потомком первого пути.В Python3 вы можете использовать
PurePath.relative_to
:источник
os.pardir
более надежна, чем проверка на наличие..
(хотя и не так много других соглашений).os.relpath
более мощным, так как он обрабатывает..
иPurePath.relative_to()
не делает? Я что-то упускаю?Другой вариант
источник
os.pardir
хотя можно проверить наличие перед двумя возможными относительными путями).Описание предложения jme с использованием pathlib в Python 3.
источник
dir1.relative_to(dir2)
что даст PosixPath ('.'), Если они одинаковы. Когда вы используете,if dir2 in dir1.parents
это исключает личность. Если кто-то сравнивает пути и хочет работать,relative_to()
если они совместимы с путями, лучшим решением может бытьif dir2 in (dir1 / 'x').parents
илиif dir2 in dir1.parents or dir2 == dir1
. Тогда все случаи совместимости пути покрыты.Чистый Python2 без депо:
источник
cwd
иpath
то же самое. он должен проверить первый , если те два одинаковы и возврат либо""
или"."
Изменить: см. Ответ JME для лучшего пути с Python3.
Используя pathlib, у вас есть следующее решение:
Допустим, мы хотим проверить,
son
является ли потомок объектаparent
обоимиPath
объектами. Мы можем получить список частей в пути сlist(parent.parts)
. Затем мы просто проверяем, что начало сына равно списку сегментов родителя.Если вы хотите получить оставшуюся часть, вы можете просто сделать
Это строка, но вы, конечно, можете использовать ее как конструктор другого объекта Path.
источник
parent in son.parents
и, если это так, получить остаток с помощьюson.relative_to(parent)
.