关于python:使用pathlib的relative_to在同一级别上的目录

Using pathlib's relative_to for directories on the same level

python库pathlib提供了Path.relative_to。 如果一个路径是另一路径的子路径,则此功能可以正常工作,如下所示:

1
2
3
4
5
6
from pathlib import Path
foo = Path("C:\\foo")
bar = Path("C:\\foo\\bar")
bar.relative_to(foo)

> WindowsPath('bar')

但是,如果两个路径处于同一级别,则relative_to不起作用。

1
2
3
4
baz = Path("C:\\baz")
foo.relative_to(baz)

> ValueError: 'C:\\foo' does not start with 'C:\\baz'

我希望结果是

1
WindowsPath("..\\baz")

函数os.path.relpath可以正确执行此操作:

1
2
3
4
5
6
import os
foo ="C:\\foo"
bar ="C:\\bar"
os.path.relpath(foo, bar)

> '..\\foo'

有没有办法使用pathlib.Path实现os.path.relpath的功能?


第一部分解决了OP的问题,尽管如果像我一样,他真的想要相对于公共根的解决方案,那么第二部分为他解决了问题。 第三部分描述了我最初是如何使用它的,并出于兴趣着想。

相对路径

最近,与Python 3.4-6一样,os.path模块已扩展为接受pathlib.Path对象。 但是,在以下情况下,它不返回Path对象,并且被迫包装结果。

1
2
3
4
5
foo = Path("C:\\foo")
baz = Path("C:\\baz")
Path(os.path.relpath(foo, baz))

> Path("..\\foo")

共同路径

我怀疑您确实在寻找相对于共同根的路径。 如果是这样,那么EOL的以下内容更有用

1
2
3
Path(os.path.commonpath([foo, baz]))

> Path('c:/root')

通用前缀

在触及os.path.commonpath之前,我已经使用过os.path.comonprefix

1
2
3
4
5
foo = Path("C:\\foo")
baz = Path("C:\\baz")
baz.relative_to(os.path.commonprefix([baz,foo]))

> Path('baz')

但是请注意,您不应该在这种情况下使用它(请参阅commonprefix:是的,那个古老的栗子)

1
2
3
4
5
6
7
8
9
10
foo = Path("C:\
oute66\\foo"
)
baz = Path("C:\
oute44\\baz"
)
baz.relative_to(os.path.commonprefix([baz,foo]))

> ...
> ValueError : `c:\
oute44\baz` does not start with `C:\
oute`

而是J. F. Sebastian的下一个。

1
2
3
Path(*os.path.commonprefix([foo.parts, baz.parts]))

> Path('c:/root')

...或者如果您感到冗长...

1
2
from itertools import takewhile
Path(*[set(i).pop() for i in (takewhile(lambda x : x[0]==x[1], zip(foo.parts, baz.parts)))])