如何在没有系统特定的情况下获得 pathlib 的 unix 路径处理好东西,例如 Path.resolve() 将 /tmp 更改为 /private/tmp

How to get pathlib’s unix path handling goodies without the system specific ones, eg Path.resolve() changes /tmp to /private/tmp

使用 pathlib 遇到一个有趣的案例,我用它来表示 android 设备上的路径,而不是 python 正在 运行 正在使用的机器。是否仍然可以利用 pathlib 的含糖语法和解决 unix 范围内的老生常谈的能力,例如相对路径“../../”而不解决设备特定的符号链接,例如“/tmp/path”->“/private /tmp/path”?

在大多数情况下,pathlib 使处理设备上的路径变得非常容易,但是我 运行 在不使用主机 python 机器的符号链接解析的情况下想要解析设备上的路径时遇到了问题机制。

我喜欢使用 pathlib 而不是字符串。是否可以使用 Path 对象进行路径操作和操作,然后将最终文件命令发送到 ssh 进入的设备?

我唯一想要的 resolve 是能够转 (Path(“/tmp/analysis/ptool”) / “../../“).resolve 照顾 .. 但不是将 /tmp 更改为 /private/tmp,这不是我要使用此路径命令的设备上的符号链接。

这个例子有点微不足道“只用字符串来做”,但我想应用它的组织和自动化明显更清晰,更容易阅读作为路径对象而不是字符串。如果可以的话,让它发挥作用就太好了。

In [1]: import pathlib

In [2]: from pathlib import Path

In [3]: Path('/tmp/hello').resolve()
Out[3]: PosixPath('/private/tmp/hello')

MacOS,Python3.7.3

/private/tmp/tmp 内容实际存储在 Mac OS 上的位置。在这个平台上,/tmp 是一个符号链接。完全不用Python就可以从操作系统上看出来:

$ ls -l /tmp
lrwxr-xr-x 1 root wheel 11 Oct 22  2018 /tmp -> private/tmp
$ (cd /tmp && pwd -P)
/private/tmp

pathlib.Path.resolve() 将符号链接替换为它们指向的绝对路径,因此它完全符合您的要求。

Why is /tmp a symlink to /private/tmp? on our sister site Ask Different

在这种情况下使用整个 Path 似乎是错误的,因为它暴露了像 stat which will try and operate on your local system, rather than the remote device. using a PurePosixPath 这样的方法看起来更好,因为它没有暴露那么多,而且很容易添加 resolve 派生的方法 class:

from pathlib import PurePosixPath

class ResolvingPosixPath(PurePosixPath):
    def resolve(self):
        if not self.is_absolute():
            raise ValueError('only able to resolve absolute paths')

        sep = self._flavour.sep
        path = ''

        for name in str(self).split(sep):
            if not name or name == '.':
                # current dir
                continue
            if name == '..':
                # parent dir
                path, _, _ = path.rpartition(sep)
                continue

            path = path + sep + name

        return path or sep

我已经从 pathlib._PosixFlavour.resolve 中提取了相关代码,并且 如果方便的话,您显然可以自由使用更短的 class 名称!

这可以按照您的建议使用:

hello = ResolvingPosixPath('/tmp') / 'hello'
print(hello.resolve())

给我 '/tmp/hello'