python库pathlib
提供Path.relative_to
。如果一个路径是另一个路径的子路径,则此函数可以正常工作,如下所示:
In [12]: from pathlib import Path
In [13]: foo = Path("C:\\foo")
In [14]: bar = Path("C:\\foo\\bar")
In [15]: bar.relative_to(foo)
Out[15]: WindowsPath('bar')
但是,如果两个路径位于相同级别,则relative_to
不起作用。
In [16]: baz = Path("C:\\baz")
In [17]: foo.relative_to(baz)
--------------------------------------------------------------------------
ValueError: 'C:\\foo' does not start with 'C:\\baz'
我希望结果是
WindowsPath("..\\baz")
函数os.path.relpath
正确执行此操作:
In [18]: import os
In [19]: foo = "C:\\foo"
In [20]: bar = "C:\\bar"
In [21]: os.path.relpath(foo, bar)
Out[21]: '..\\foo'
有没有办法使用os.path.relpath
来实现pathlib.Path
的功能?
答案 0 :(得分:6)
第一部分解决了OP的问题,但是如果像我一样,他真的想要相对于共同根的解决方案,那么第二部分就为他解决了这个问题。第三部分描述了我最初是如何接近它并为了利益而保留的。
最近,与Python 3.4-6一样,os.path
模块已扩展为接受pathlib.Path
个对象。在下面的例子中,它不返回Path对象,并且强制一个包装结果。
foo = Path("C:\\foo")
baz = Path("C:\\baz")
Path(os.path.relpath(foo, baz))
> Path("..\\foo")
我怀疑你是否真的在寻找一个相对于共同根的路径。如果是这种情况,则EOL中的以下内容更有用
Path(os.path.commonpath([foo, baz]))
> Path('c:/root')
在我开始os.path.commonpath
之前,我曾使用os.path.comonprefix
。
foo = Path("C:\\foo")
baz = Path("C:\\baz")
baz.relative_to(os.path.commonprefix([baz,foo]))
> Path('baz')
但要预先警告你不应该在这种情况下使用它(见commonprefix : Yes, that old chestnut)
foo = Path("C:\\route66\\foo")
baz = Path("C:\\route44\\baz")
baz.relative_to(os.path.commonprefix([baz,foo]))
> ...
> ValueError : `c:\\route44\baz` does not start with `C:\\route`
,而是来自J. F. Sebastian的以下内容。
Path(*os.path.commonprefix([foo.parts, baz.parts]))
> Path('c:/root')
......或者如果你感到啰嗦......
from itertools import takewhile
Path(*[set(i).pop() for i in (takewhile(lambda x : x[0]==x[1], zip(foo.parts, baz.parts)))])
答案 1 :(得分:3)
这让我很烦,所以这是一个仅基于pathlib的版本,我认为它可以完成os.path.relpath
的工作。
def relpath(path_to, path_from):
path_to = Path(path_to).resolve()
path_from = Path(path_from).resolve()
try:
for p in (*reversed(path_from.parents), path_from):
head, tail = p, path_to.relative_to(p)
except ValueError: # Stop when the paths diverge.
pass
return Path('../' * (len(path_from.parents) - len(head.parents))).joinpath(tail)