簡體   English   中英

對同級目錄使用 pathlib 的 relative_to

[英]Using pathlib's relative_to for directories on the same level

python 庫pathlib提供Path.relative_to 如果一條路徑是另一條路徑的子路徑,則 function 可以正常工作,如下所示:

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

> WindowsPath('bar')

但是,如果兩條路徑在同一層,則relative_to不起作用。

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

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

我希望結果是

WindowsPath("..\\baz")

function os.path.relpath正確執行此操作:

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 對象,並且強制包裝結果。

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 :是的,那個老栗子

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)))])

這讓我很煩惱,所以這里有一個只有 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)

@Brett_Ryland 的 relpath for pathlib 的遞歸版本。 我發現它更具可讀性,並且在大多數情況下它會在第一次try時成功,因此它應該具有與原始relative_to function 相似的性能:

def relative(target: Path, origin: Path):
    """ return path of target relative to origin """
    try:
        return Path(target).resolve().relative_to(Path(origin).resolve())
    except ValueError as e: # target does not start with origin
        # recursion with origin (eventually origin is root so try will succeed)
        return Path('..').joinpath(relative(target, Path(origin).parent))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM