34

python ライブラリpathlibが提供しますPath.relative_to。次のように、一方のパスがもう一方のパスのサブパスである場合、この関数は正常に機能します。

from pathlib import Path
foo = Path("C:\\foo")
bar = Path("C:\\foo\\bar")
bar.relative_to(foo)

> WindowsPath('bar')

ただし、2 つのパスが同じレベルにある場合、relative_toは機能しません。

baz = Path("C:\\baz")
foo.relative_to(baz)

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

私は結果が

WindowsPath("..\\baz")

関数os.path.relpathはこれを正しく行います。

import os
foo = "C:\\foo"
bar = "C:\\bar"
os.path.relpath(foo, bar)

> '..\\foo'

os.path.relpathを使用する機能を実現する方法はありpathlib.Pathますか?

4

2 に答える 2

34

最初のセクションでは OP の問題を解決しますが、私のように、共通のルートに関連するソリューションが本当に必要な場合は、2 番目のセクションでそれを解決します。3 番目のセクションでは、私が最初にどのようにアプローチしたかを説明します。

相対パス

最近、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`

ではなく、JF 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)))])
于 2017-04-25T14:38:34.843 に答える