"pathlib" --- 面向对象的文件系统路径
************************************

Added in version 3.4.

**源代码：**Lib/pathlib.py

======================================================================

该模块提供表示文件系统路径的类，其语义适用于不同的操作系统。路径类被分
为提供纯计算操作而没有 I/O 的 纯路径，以及从纯路径继承而来但提供 I/O
操作的 具体路径。

[图片： 继承关系图显示了 pathlib 中所有可用的类。 最基础的类是
PurePath，它有三个直接子类： PurePosixPath, PureWindowsPath 和 Path。
在这四个类之外，还有两个使用多重继承的类： PosixPath 子类
PurePosixPath 和 Path，以及 WindowsPath 子类 PureWindowsPath 和 Path。
][图片]

如果以前从未用过此模块，或不确定哪个类适合完成任务，那要用的可能就是
"Path"。它在运行代码的平台上实例化为 具体路径。

在一些用例中纯路径很有用，例如：

1. 如果你想要在 Unix 设备上操作 Windows 路径（或者相反）。你不应在
   Unix 上实例化一个 "WindowsPath"，但是你可以实例化 "PureWindowsPath"
   。

2. 你只想操作路径但不想实际访问操作系统。在这种情况下，实例化一个纯路
   径是有用的，因为它们没有任何访问操作系统的操作。

参见: **PEP 428**：pathlib 模块 -- 面向对象的文件系统路径。

参见: 对于底层的路径字符串操作，你也可以使用 "os.path" 模块。


基础使用
========

导入主类:

   >>> from pathlib import Path

列出子目录:

   >>> p = Path('.')
   >>> [x for x in p.iterdir() if x.is_dir()]
   [PosixPath('.hg'), PosixPath('docs'), PosixPath('dist'),
    PosixPath('__pycache__'), PosixPath('build')]

列出当前目录树下的所有 Python 源代码文件:

   >>> list(p.glob('**/*.py'))
   [PosixPath('test_pathlib.py'), PosixPath('setup.py'),
    PosixPath('pathlib.py'), PosixPath('docs/conf.py'),
    PosixPath('build/lib/pathlib.py')]

在目录树中移动:

   >>> p = Path('/etc')
   >>> q = p / 'init.d' / 'reboot'
   >>> q
   PosixPath('/etc/init.d/reboot')
   >>> q.resolve()
   PosixPath('/etc/rc.d/init.d/halt')

查询路径的属性:

   >>> q.exists()
   True
   >>> q.is_dir()
   False

打开一个文件:

   >>> with q.open() as f: f.readline()
   ...
   '#!/bin/bash\n'


纯路径
======

纯路径对象提供了不实际访问文件系统的路径处理操作。有三种方式来访问这些
类，也是不同的风格：

class pathlib.PurePath(*pathsegments)

   一个通用的类，代表当前系统的路径风格（实例化为 "PurePosixPath" 或者
   "PureWindowsPath"）:

      >>> PurePath('setup.py')      # Running on a Unix machine
      PurePosixPath('setup.py')

   *pathsegments* 的每个元素既可以是代表一个路径段的字符串，也可以是实
   现了 "os.PathLike" 接口的对象，其中 "__fspath__()" 方法返回一个字符
   串，例如另一个路径对象:

      >>> PurePath('foo', 'some/path', 'bar')
      PurePosixPath('foo/some/path/bar')
      >>> PurePath(Path('foo'), Path('bar'))
      PurePosixPath('foo/bar')

   当 *pathsegments* 为空的时候，假定为当前目录:

      >>> PurePath()
      PurePosixPath('.')

   如果某个段为绝对路径，则其前面的所有段都会被忽略 (类似
   "os.path.join()"):

      >>> PurePath('/etc', '/usr', 'lib64')
      PurePosixPath('/usr/lib64')
      >>> PureWindowsPath('c:/Windows', 'd:bar')
      PureWindowsPath('d:bar')

   在 Windows 上，当遇到带根符号的路径段 (如 "r'\foo'") 时驱动器将不会
   被重置:

      >>> PureWindowsPath('c:/Windows', '/Program Files')
      PureWindowsPath('c:/Program Files')

   假斜杠和单个点号会被消除，但双点号 ("'..'") 和打头的双斜杠 ("'//'")
   不会，因为这会出于各种原因改变路径的实际含义 (例如符号链接、UNC 路
   径等):

      >>> PurePath('foo//bar')
      PurePosixPath('foo/bar')
      >>> PurePath('//foo/bar')
      PurePosixPath('//foo/bar')
      >>> PurePath('foo/./bar')
      PurePosixPath('foo/bar')
      >>> PurePath('foo/../bar')
      PurePosixPath('foo/../bar')

   （一个很 naïve 的做法是让 "PurePosixPath('foo/../bar')" 等同于
   "PurePosixPath('bar')"，如果 "foo" 是一个指向其他目录的符号链接那么
   这个做法就将出错）

   纯路径对象实现了 "os.PathLike" 接口，允许它们在任何接受此接口的地方
   使用。

   在 3.6 版本发生变更: 添加了 "os.PathLike" 接口支持。

class pathlib.PurePosixPath(*pathsegments)

   一个 "PurePath" 的子类，路径风格不同于 Windows 文件系统:

      >>> PurePosixPath('/etc')
      PurePosixPath('/etc')

   *pathsegments* 参数的指定和 "PurePath" 相同。

class pathlib.PureWindowsPath(*pathsegments)

   "PurePath" 的一个子类，此路径风格代表 Windows 文件系统路径，包括
   UNC paths:

      >>> PureWindowsPath('c:/Program Files/')
      PureWindowsPath('c:/Program Files')
      >>> PureWindowsPath('//server/share/file')
      PureWindowsPath('//server/share/file')

   *pathsegments* 参数的指定和 "PurePath" 相同。

无论你正运行什么系统，你都可以实例化这些类，因为它们提供的操作不做任何
系统调用。


通用性质
--------

路径是不可变并且 *hashable*。 相同风格的路径可以排序和比较。 这此特性
会尊重对应风格的大小写转换语义。:

   >>> PurePosixPath('foo') == PurePosixPath('FOO')
   False
   >>> PureWindowsPath('foo') == PureWindowsPath('FOO')
   True
   >>> PureWindowsPath('FOO') in { PureWindowsPath('foo') }
   True
   >>> PureWindowsPath('C:') < PureWindowsPath('d:')
   True

不同风格的路径比较得到不等的结果并且无法被排序:

   >>> PureWindowsPath('foo') == PurePosixPath('foo')
   False
   >>> PureWindowsPath('foo') < PurePosixPath('foo')
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: '<' not supported between instances of 'PureWindowsPath' and 'PurePosixPath'


运算符
------

斜杠操作符可以帮助创建子路径，如 "os.path.join()"。 如果参数为一个绝对
路径，则之前的路径会被忽略。 在 Windows 上，当参数为一个带根符号的相对
路径 (如 "r'\foo'") 时驱动器将不会被重置:

   >>> p = PurePath('/etc')
   >>> p
   PurePosixPath('/etc')
   >>> p / 'init.d' / 'apache2'
   PurePosixPath('/etc/init.d/apache2')
   >>> q = PurePath('bin')
   >>> '/usr' / q
   PurePosixPath('/usr/bin')
   >>> p / '/an_absolute_path'
   PurePosixPath('/an_absolute_path')
   >>> PureWindowsPath('c:/Windows', '/Program Files')
   PureWindowsPath('c:/Program Files')

文件对象可用于任何接受 "os.PathLike" 接口实现的地方。

   >>> import os
   >>> p = PurePath('/etc')
   >>> os.fspath(p)
   '/etc'

路径的字符串表示法为它自己原始的文件系统路径（以原生形式，例如在
Windows 下使用反斜杠）。你可以传递给任何需要字符串形式路径的函数。

   >>> p = PurePath('/etc')
   >>> str(p)
   '/etc'
   >>> p = PureWindowsPath('c:/Program Files')
   >>> str(p)
   'c:\\Program Files'

类似地，在路径上调用 "bytes" 将原始文件系统路径作为字节对象给出，就像
被 "os.fsencode()" 编码一样:

   >>> bytes(p)
   b'/etc'

备注:

  只推荐在 Unix 下调用 "bytes"。在 Windows， unicode 形式是文件系统路
  径的规范表示法。


访问个别部分
------------

为了访问路径独立的部分 （组件），使用以下特征属性：

PurePath.parts

   一个元组，可以访问路径的多个组件:

      >>> p = PurePath('/usr/bin/python3')
      >>> p.parts
      ('/', 'usr', 'bin', 'python3')

      >>> p = PureWindowsPath('c:/Program Files/PSF')
      >>> p.parts
      ('c:\\', 'Program Files', 'PSF')

   （注意盘符和本地根目录是如何重组的）


方法和特征属性
--------------

纯路径提供以下方法和特征属性：

PurePath.drive

   一个表示驱动器盘符或命名的字符串，如果存在:

      >>> PureWindowsPath('c:/Program Files/').drive
      'c:'
      >>> PureWindowsPath('/Program Files/').drive
      ''
      >>> PurePosixPath('/etc').drive
      ''

   UNC 分享也被认作驱动器:

      >>> PureWindowsPath('//host/share/foo.txt').drive
      '\\\\host\\share'

PurePath.root

   一个表示（本地或全局）根的字符串，如果存在:

      >>> PureWindowsPath('c:/Program Files/').root
      '\\'
      >>> PureWindowsPath('c:Program Files/').root
      ''
      >>> PurePosixPath('/etc').root
      '/'

   UNC 分享一样拥有根:

      >>> PureWindowsPath('//host/share').root
      '\\'

   如果路径以超过两个连续斜框打头，"PurePosixPath" 会合并它们:

      >>> PurePosixPath('//etc').root
      '//'
      >>> PurePosixPath('///etc').root
      '/'
      >>> PurePosixPath('////etc').root
      '/'

   备注:

     此行为符合 *The Open Group Base Specifications Issue 6*,
     paragraph 4.11 Pathname Resolution:*"以连续两个斜杠打头的路径名可
     能会以具体实现所定义的方式被解读，但是两个以上的前缀斜杠则应当被
     当作一个斜杠来处理。"*

PurePath.anchor

   驱动器和根的联合:

      >>> PureWindowsPath('c:/Program Files/').anchor
      'c:\\'
      >>> PureWindowsPath('c:Program Files/').anchor
      'c:'
      >>> PurePosixPath('/etc').anchor
      '/'
      >>> PureWindowsPath('//host/share').anchor
      '\\\\host\\share\\'

PurePath.parents

   提供访问此路径的逻辑祖先的不可变序列:

      >>> p = PureWindowsPath('c:/foo/bar/setup.py')
      >>> p.parents[0]
      PureWindowsPath('c:/foo/bar')
      >>> p.parents[1]
      PureWindowsPath('c:/foo')
      >>> p.parents[2]
      PureWindowsPath('c:/')

   在 3.10 版本发生变更: parents 序列现在支持 *切片* 和负的索引值。

PurePath.parent

   此路径的逻辑父路径:

      >>> p = PurePosixPath('/a/b/c/d')
      >>> p.parent
      PurePosixPath('/a/b/c')

   你不能超过一个 anchor 或空路径:

      >>> p = PurePosixPath('/')
      >>> p.parent
      PurePosixPath('/')
      >>> p = PurePosixPath('.')
      >>> p.parent
      PurePosixPath('.')

   备注:

     这是一个单纯的词法操作，因此有以下行为:

        >>> p = PurePosixPath('foo/..')
        >>> p.parent
        PurePosixPath('foo')

     如果你想要向上遍历任意文件系统路径，建议首先调用 "Path.resolve()"
     以便解析符号链接并消除 "".."" 部分。

PurePath.name

   一个表示最后路径组件的字符串，排除了驱动器与根目录，如果存在的话:

      >>> PurePosixPath('my/library/setup.py').name
      'setup.py'

   UNC 驱动器名不被考虑:

      >>> PureWindowsPath('//some/share/setup.py').name
      'setup.py'
      >>> PureWindowsPath('//some/share').name
      ''

PurePath.suffix

   最终组件的文件扩展名（如果有）：

      >>> PurePosixPath('my/library/setup.py').suffix
      '.py'
      >>> PurePosixPath('my/library.tar.gz').suffix
      '.gz'
      >>> PurePosixPath('my/library').suffix
      ''

PurePath.suffixes

   一个路径文件扩展名的列表：

      >>> PurePosixPath('my/library.tar.gar').suffixes
      ['.tar', '.gar']
      >>> PurePosixPath('my/library.tar.gz').suffixes
      ['.tar', '.gz']
      >>> PurePosixPath('my/library').suffixes
      []

PurePath.stem

   最后一个路径组件，除去后缀:

      >>> PurePosixPath('my/library.tar.gz').stem
      'library.tar'
      >>> PurePosixPath('my/library.tar').stem
      'library'
      >>> PurePosixPath('my/library').stem
      'library'

PurePath.as_posix()

   返回使用正斜杠（"/"）的路径字符串:

      >>> p = PureWindowsPath('c:\\windows')
      >>> str(p)
      'c:\\windows'
      >>> p.as_posix()
      'c:/windows'

PurePath.as_uri()

   将路径表示为 "file" URI。 如果路径不是绝对路径，将引发 "ValueError"
   。

   >>> p = PurePosixPath('/etc/passwd')
   >>> p.as_uri()
   'file:///etc/passwd'
   >>> p = PureWindowsPath('c:/Windows')
   >>> p.as_uri()
   'file:///c:/Windows'

PurePath.is_absolute()

   返回此路径是否为绝对路径。如果路径同时拥有驱动器符与根路径（如果风
   格允许）则将被认作绝对路径。

      >>> PurePosixPath('/a/b').is_absolute()
      True
      >>> PurePosixPath('a/b').is_absolute()
      False

      >>> PureWindowsPath('c:/a/b').is_absolute()
      True
      >>> PureWindowsPath('/a/b').is_absolute()
      False
      >>> PureWindowsPath('c:').is_absolute()
      False
      >>> PureWindowsPath('//some/share').is_absolute()
      True

PurePath.is_relative_to(other)

   返回此路径是否相对于 *other* 的路径。

   >>> p = PurePath('/etc/passwd')
   >>> p.is_relative_to('/etc')
   True
   >>> p.is_relative_to('/usr')
   False

   此方法是基于字符串的；它不会访问文件系统也不会对 "".."" 部分进行特
   殊处理。 以下代码是等价的：

   >>> u = PurePath('/usr')
   >>> u == p or u in p.parents
   False

   Added in version 3.9.

   Deprecated since version 3.12, will be removed in version 3.14: 传
   入附加参数的做法已被弃用；如果提供了附加参数，它们将与 *other* 合并
   。

PurePath.is_reserved()

   在 "PureWindowsPath"，如果路径是被 Windows 保留的则返回 "True"，否
   则 "False"。在 "PurePosixPath"，总是返回 "False"。

   >>> PureWindowsPath('nul').is_reserved()
   True
   >>> PurePosixPath('nul').is_reserved()
   False

   对保留路径的文件系统调用可能会莫名其妙地失败或产生意想不到的效果。

PurePath.joinpath(*pathsegments)

   调用此方法等同于依次将路径与给定的每个 *pathsegments* 组合到一起:

      >>> PurePosixPath('/etc').joinpath('passwd')
      PurePosixPath('/etc/passwd')
      >>> PurePosixPath('/etc').joinpath(PurePosixPath('passwd'))
      PurePosixPath('/etc/passwd')
      >>> PurePosixPath('/etc').joinpath('init.d', 'apache2')
      PurePosixPath('/etc/init.d/apache2')
      >>> PureWindowsPath('c:').joinpath('/Program Files')
      PureWindowsPath('c:/Program Files')

PurePath.match(pattern, *, case_sensitive=None)

   将此路径与所提供的 glob 样式匹配。如果匹配成功，则返回``True``，否
   则返回``False``。

   如果 *pattern* 是相对路径，则路径既可以是相对路径，也可以是绝对路径
   ，匹配从右边的开始：

      >>> PurePath('a/b.py').match('*.py')
      True
      >>> PurePath('/a/b/c.py').match('b/*.py')
      True
      >>> PurePath('/a/b/c.py').match('a/*.py')
      False

   If *pattern* is absolute, the path must be absolute, and the whole
   path must match:

      >>> PurePath('/a.py').match('/*.py')
      True
      >>> PurePath('a/b.py').match('/*.py')
      False

   The *pattern* may be another path object; this speeds up matching
   the same pattern against multiple files:

      >>> pattern = PurePath('*.py')
      >>> PurePath('a/b.py').match(pattern)
      True

   备注:

     The recursive wildcard ""**"" isn't supported by this method (it
     acts like non-recursive ""*"".)

   在 3.12 版本发生变更: Accepts an object implementing the
   "os.PathLike" interface.

   与其他方法一样，是否大小写敏感遵循平台的默认规则:

      >>> PurePosixPath('b.py').match('*.PY')
      False
      >>> PureWindowsPath('b.py').match('*.PY')
      True

   将 *case_sensitive* 设为 "True" 或 "False" 来覆盖此行为。

   在 3.12 版本发生变更: 增加了 *case_sensitive* 形参。

PurePath.relative_to(other, walk_up=False)

   计算此路径相对于 *other* 所表示路径的版本。 如果不可计算，则引发
   "ValueError":

      >>> p = PurePosixPath('/etc/passwd')
      >>> p.relative_to('/')
      PurePosixPath('etc/passwd')
      >>> p.relative_to('/etc')
      PurePosixPath('passwd')
      >>> p.relative_to('/usr')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "pathlib.py", line 941, in relative_to
          raise ValueError(error_message.format(str(self), str(formatted)))
      ValueError: '/etc/passwd' is not in the subpath of '/usr' OR one path is relative and the other is absolute.

   当 *walk_up* 为（默认的）假值时，路径必须以 *other* 开始。 当参数为
   真值时，可能会添加 ".." 条目以形成相对路径。 在所有其他情况下，例如
   路径引用了不同的驱动器，则会引发 "ValueError"。:

      >>> p.relative_to('/usr', walk_up=True)
      PurePosixPath('../etc/passwd')
      >>> p.relative_to('foo', walk_up=True)
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "pathlib.py", line 941, in relative_to
          raise ValueError(error_message.format(str(self), str(formatted)))
      ValueError: '/etc/passwd' is not on the same drive as 'foo' OR one path is relative and the other is absolute.

   警告:

     该函数是 "PurePath" 的一部分并适用于字符串。 它不会检查或访问下层
     的文件结构体。 这可能会影响 *walk_up* 选项因为它假定路径中不存在
     符号链接；如果需要处理符号链接请先调用 "resolve()"。

   在 3.12 版本发生变更: 增加了 *walk_up* 形参数（原本的行为与
   "walk_up=False" 相同）。

   Deprecated since version 3.12, will be removed in version 3.14: 传
   入附加位置参数的做法已被弃用；如果提供的话，它们将与 *other* 合并。

PurePath.with_name(name)

   返回一个新的路径并修改 "name"。如果原本路径没有 name，ValueError 被
   抛出:

      >>> p = PureWindowsPath('c:/Downloads/pathlib.tar.gz')
      >>> p.with_name('setup.py')
      PureWindowsPath('c:/Downloads/setup.py')
      >>> p = PureWindowsPath('c:/')
      >>> p.with_name('setup.py')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/home/antoine/cpython/default/Lib/pathlib.py", line 751, in with_name
          raise ValueError("%r has an empty name" % (self,))
      ValueError: PureWindowsPath('c:/') has an empty name

PurePath.with_stem(stem)

   返回一个带有修改后 "stem" 的新路径。 如果原路径没有名称，则会引发
   ValueError:

      >>> p = PureWindowsPath('c:/Downloads/draft.txt')
      >>> p.with_stem('final')
      PureWindowsPath('c:/Downloads/final.txt')
      >>> p = PureWindowsPath('c:/Downloads/pathlib.tar.gz')
      >>> p.with_stem('lib')
      PureWindowsPath('c:/Downloads/lib.gz')
      >>> p = PureWindowsPath('c:/')
      >>> p.with_stem('')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/home/antoine/cpython/default/Lib/pathlib.py", line 861, in with_stem
          return self.with_name(stem + self.suffix)
        File "/home/antoine/cpython/default/Lib/pathlib.py", line 851, in with_name
          raise ValueError("%r has an empty name" % (self,))
      ValueError: PureWindowsPath('c:/') has an empty name

   Added in version 3.9.

PurePath.with_suffix(suffix)

   返回一个新的路径并修改 "suffix"。如果原本的路径没有后缀，新的
   *suffix* 则被追加以代替。如果 *suffix* 是空字符串，则原本的后缀被移
   除:

      >>> p = PureWindowsPath('c:/Downloads/pathlib.tar.gz')
      >>> p.with_suffix('.bz2')
      PureWindowsPath('c:/Downloads/pathlib.tar.bz2')
      >>> p = PureWindowsPath('README')
      >>> p.with_suffix('.txt')
      PureWindowsPath('README.txt')
      >>> p = PureWindowsPath('README.txt')
      >>> p.with_suffix('')
      PureWindowsPath('README')

PurePath.with_segments(*pathsegments)

   通过组合给定的 *pathsegments* 创建一个相同类型的新路径对象。 每当创
   建派生路径，如从 "parent" 和 "relative_to()" 创建时都会调用此方法。
   子类可以覆盖此方法以便向派生路径传递信息，例如:

      from pathlib import PurePosixPath

      class MyPath(PurePosixPath):
          def __init__(self, *pathsegments, session_id):
              super().__init__(*pathsegments)
              self.session_id = session_id

          def with_segments(self, *pathsegments):
              return type(self)(*pathsegments, session_id=self.session_id)

      etc = MyPath('/etc', session_id=42)
      hosts = etc / 'hosts'
      print(hosts.session_id)  # 42

   Added in version 3.12.


具体路径
========

具体路径是纯路径的子类。除了后者提供的操作之外，它们还提供了对路径对象
进行系统调用的方法。有三种方法可以实例化具体路径:

class pathlib.Path(*pathsegments)

   一个 "PurePath" 的子类，此类以当前系统的路径风格表示路径（实例化为
   "PosixPath" 或 "WindowsPath"）:

      >>> Path('setup.py')
      PosixPath('setup.py')

   *pathsegments* 参数的指定和 "PurePath" 相同。

class pathlib.PosixPath(*pathsegments)

   一个 "Path" 和 "PurePosixPath" 的子类，此类表示一个非 Windows 文件
   系统的具体路径:

      >>> PosixPath('/etc')
      PosixPath('/etc')

   *pathsegments* 参数的指定和 "PurePath" 相同。

class pathlib.WindowsPath(*pathsegments)

   "Path" 和 "PureWindowsPath" 的子类，从类表示一个 Windows 文件系统的
   具体路径:

      >>> WindowsPath('c:/Program Files/')
      WindowsPath('c:/Program Files')

   *pathsegments* 参数的指定和 "PurePath" 相同。

你只能实例化与当前系统风格相同的类（允许系统调用作用于不兼容的路径风格
可能在应用程序中导致缺陷或失败）:

   >>> import os
   >>> os.name
   'posix'
   >>> Path('setup.py')
   PosixPath('setup.py')
   >>> PosixPath('setup.py')
   PosixPath('setup.py')
   >>> WindowsPath('setup.py')
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
     File "pathlib.py", line 798, in __new__
       % (cls.__name__,))
   NotImplementedError: cannot instantiate 'WindowsPath' on your system

某些具体路径方法在一个系统调用失败时（例如由于路径不存在）可能引发
"OSError"。


扩展和计算路径
--------------

classmethod Path.home()

   返回一个表示用户家目录的新路径对象（与带 "~" 构造的
   "os.path.expanduser()" 所返回的相同）。 如果无法解析家目录，则会引
   发 "RuntimeError"。

      >>> Path.home()
      PosixPath('/home/antoine')

   Added in version 3.5.

Path.expanduser()

   返回带有扩展 "~" 和 "~user" 构造的新路径，与 "os.path.expanduser()"
   所返回的相同。 如果无法解析家目录，则会引发 "RuntimeError"。

      >>> p = PosixPath('~/films/Monty Python')
      >>> p.expanduser()
      PosixPath('/home/eric/films/Monty Python')

   Added in version 3.5.

classmethod Path.cwd()

   返回一个新的表示当前目录的路径对象（和 "os.getcwd()" 返回的相同）:

      >>> Path.cwd()
      PosixPath('/home/antoine/pathlib')

Path.absolute()

   改为绝对路径，不会执行正规化或解析符号链接。 返回一个新的路径对象:

      >>> p = Path('tests')
      >>> p
      PosixPath('tests')
      >>> p.absolute()
      PosixPath('/home/antoine/pathlib/tests')

Path.resolve(strict=False)

   将路径绝对化，解析任何符号链接。返回新的路径对象:

      >>> p = Path()
      >>> p
      PosixPath('.')
      >>> p.resolve()
      PosixPath('/home/antoine/pathlib')

   "".."" 组件也将被消除（只有这一种方法这么做）:

      >>> p = Path('docs/../setup.py')
      >>> p.resolve()
      PosixPath('/home/antoine/pathlib/setup.py')

   If the path doesn't exist and *strict* is "True",
   "FileNotFoundError" is raised.  If *strict* is "False", the path is
   resolved as far as possible and any remainder is appended without
   checking whether it exists.  If an infinite loop is encountered
   along the resolution path, "RuntimeError" is raised.

   在 3.6 版本发生变更: 增加了 *strict* 参数（3.6 之前的行为是默认采用
   strict 模式）。

Path.readlink()

   返回符号链接所指向的路径（即 "os.readlink()" 的返回值）:

      >>> p = Path('mylink')
      >>> p.symlink_to('setup.py')
      >>> p.readlink()
      PosixPath('setup.py')

   Added in version 3.9.


查询文件类型和状态
------------------

在 3.8 版本发生变更: 对于包含 OS 层级无法表示字符的路径，"exists()",
"is_dir()", "is_file()", "is_mount()", "is_symlink()",
"is_block_device()", "is_char_device()", "is_fifo()", "is_socket()" 现
在将返回 "False" 而不是引发异常。

Path.stat(*, follow_symlinks=True)

   Return an "os.stat_result" object containing information about this
   path, like "os.stat()". The result is looked up at each call to
   this method.

   此方法通常会跟随符号链接；要对 symlink 使用 stat 请添加参数
   "follow_symlinks=False"，或者使用 "lstat()"。

      >>> p = Path('setup.py')
      >>> p.stat().st_size
      956
      >>> p.stat().st_mtime
      1327883547.852554

   在 3.10 版本发生变更: 增加了 *follow_symlinks* 形参。

Path.lstat()

   就和 "Path.stat()" 一样，但是如果路径指向符号链接，则是返回符号链接
   而不是目标的信息。

Path.exists(*, follow_symlinks=True)

   如果路径指向现有的文件或目录则返回 "True"。

   此方法通常会跟随符号链接；要检查符号链接是否存在，请添加参数
   "follow_symlinks=False"。

      >>> Path('.').exists()
      True
      >>> Path('setup.py').exists()
      True
      >>> Path('/etc').exists()
      True
      >>> Path('nonexistentfile').exists()
      False

   在 3.12 版本发生变更: 增加了 *follow_symlinks* 形参。

Path.is_file()

   Return "True" if the path points to a regular file (or a symbolic
   link pointing to a regular file), "False" if it points to another
   kind of file.

   当路径不存在或者是一个破损的符号链接时也会返回 "False"；其他错误（
   例如权限错误）被传播。

Path.is_dir()

   Return "True" if the path points to a directory (or a symbolic link
   pointing to a directory), "False" if it points to another kind of
   file.

   当路径不存在或者是一个破损的符号链接时也会返回 "False"；其他错误（
   例如权限错误）被传播。

Path.is_symlink()

   如果路径指向符号链接则返回 "True"， 否则 "False"。

   如果路径不存在也返回 "False"；其他错误（例如权限错误）被传播。

Path.is_junction()

   如果路径是指向一个接合点则返回 "True"，如果是其他文件类型则返回
   "False"。 目前只有 Windows 支持接合点。

   Added in version 3.12.

Path.is_mount()

   如果路径是一个 *挂载点*: 在文件系统中被其他不同文件系统挂载的位置则
   返回 "True"。 在 POSIX 上，此函数将检查 *path* 的上一级 "path/.."
   是否位于和 *path* 不同的设备中，或者 "path/.." 和 *path* 是否指向位
   于相同设置的相同 i-node --- 这应当能检测所有 Unix 和 POSIX 变种上的
   挂载点。 在 Windows 上，挂载点是被视为驱动器盘符的根目录 (例如
   "c:\")、UNC 共享目录 (例如 "\\server\share") 或已挂载的文件系统目录
   。

   Added in version 3.7.

   在 3.12 版本发生变更: 添加了 Windows 支持。

Path.is_socket()

   如果路径指向一个 Unix socket 文件（或者指向 Unix socket 文件的符号
   链接）则返回 "True"，如果指向其他类型的文件则返回 "False"。

   当路径不存在或者是一个破损的符号链接时也会返回 "False"；其他错误（
   例如权限错误）被传播。

Path.is_fifo()

   如果路径指向一个先进先出存储（或者指向先进先出存储的符号链接）则返
   回 "True" ，指向其他类型的文件则返回 "False"。

   当路径不存在或者是一个破损的符号链接时也会返回 "False"；其他错误（
   例如权限错误）被传播。

Path.is_block_device()

   如果文件指向一个块设备（或者指向块设备的符号链接）则返回 "True"，指
   向其他类型的文件则返回 "False"。

   当路径不存在或者是一个破损的符号链接时也会返回 "False"；其他错误（
   例如权限错误）被传播。

Path.is_char_device()

   如果路径指向一个字符设备（或指向字符设备的符号链接）则返回 "True"，
   指向其他类型的文件则返回 "False"。

   当路径不存在或者是一个破损的符号链接时也会返回 "False"；其他错误（
   例如权限错误）被传播。

Path.samefile(other_path)

   返回此目录是否指向与可能是字符串或者另一个路径对象的 *other_path*
   相同的文件。语义类似于 "os.path.samefile()" 与 "os.path.samestat()"
   。

   如果两者都以同一原因无法访问，则抛出 "OSError"。

      >>> p = Path('spam')
      >>> q = Path('eggs')
      >>> p.samefile(q)
      False
      >>> p.samefile('spam')
      True

   Added in version 3.5.


读写文件
--------

Path.open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)

   打开路径指向的文件，就像内置的 "open()" 函数所做的一样:

      >>> p = Path('setup.py')
      >>> with p.open() as f:
      ...     f.readline()
      ...
      '#!/usr/bin/env python3\n'

Path.read_text(encoding=None, errors=None)

   以字符串形式返回路径指向的文件的解码后文本内容。

      >>> p = Path('my_text_file')
      >>> p.write_text('Text file contents')
      18
      >>> p.read_text()
      'Text file contents'

   文件先被打开然后关闭。有和 "open()" 一样的可选形参。

   Added in version 3.5.

Path.read_bytes()

   以字节对象的形式返回路径指向的文件的二进制内容:

      >>> p = Path('my_binary_file')
      >>> p.write_bytes(b'Binary file contents')
      20
      >>> p.read_bytes()
      b'Binary file contents'

   Added in version 3.5.

Path.write_text(data, encoding=None, errors=None, newline=None)

   将文件以文本模式打开，写入 *data* 并关闭:

      >>> p = Path('my_text_file')
      >>> p.write_text('Text file contents')
      18
      >>> p.read_text()
      'Text file contents'

   同名的现有文件会被覆盖。 可选形参的含义与 "open()" 的相同。

   Added in version 3.5.

   在 3.10 版本发生变更: 增加了 *newline* 形参。

Path.write_bytes(data)

   将文件以二进制模式打开，写入 *data* 并关闭:

      >>> p = Path('my_binary_file')
      >>> p.write_bytes(b'Binary file contents')
      20
      >>> p.read_bytes()
      b'Binary file contents'

   一个同名的现存文件将被覆盖。

   Added in version 3.5.


读取目录
--------

Path.iterdir()

   当路径指向一个目录时，产生该路径下的对象的路径:

      >>> p = Path('docs')
      >>> for child in p.iterdir(): child
      ...
      PosixPath('docs/conf.py')
      PosixPath('docs/_templates')
      PosixPath('docs/make.bat')
      PosixPath('docs/index.rst')
      PosixPath('docs/_build')
      PosixPath('docs/_static')
      PosixPath('docs/Makefile')

   子条目会以任意顺序产生，并且不包括特殊条目 "'.'" 和 "'..'"。 如果迭
   代器创建之后有文件在目录中被移除或添加，是否要包括该文件所对应的路
   径对象并没有明确规定。

   如果该路径不是一个目录或是无法访问，则会引发 "OSError"。

Path.glob(pattern, *, case_sensitive=None)

   解析相对于此路径的通配符 *pattern*，产生所有匹配的文件:

      >>> sorted(Path('.').glob('*.py'))
      [PosixPath('pathlib.py'), PosixPath('setup.py'), PosixPath('test_pathlib.py')]
      >>> sorted(Path('.').glob('*/*.py'))
      [PosixPath('docs/conf.py')]

   Patterns are the same as for "fnmatch", with the addition of ""**""
   which means "this directory and all subdirectories, recursively".
   In other words, it enables recursive globbing:

      >>> sorted(Path('.').glob('**/*.py'))
      [PosixPath('build/lib/pathlib.py'),
       PosixPath('docs/conf.py'),
       PosixPath('pathlib.py'),
       PosixPath('setup.py'),
       PosixPath('test_pathlib.py')]

   This method calls "Path.is_dir()" on the top-level directory and
   propagates any "OSError" exception that is raised. Subsequent
   "OSError" exceptions from scanning directories are suppressed.

   在默认情况下，或当 *case_sensitive* 关键字参数被设为 "None" 时，该
   方法将使用特定平台的大小写规则匹配路径：通常，在 POSIX 上区分大小写
   ，而在 Windows 上不区分大小写。将 *case_sensitive* 设为 "True" 或
   "False" 可覆盖此行为。

   备注:

     在一个较大的目录树中使用 ""**"" 模式可能会消耗非常多的时间。

   Raises an auditing event "pathlib.Path.glob" with arguments "self",
   "pattern".

   在 3.11 版本发生变更: Return only directories if *pattern* ends
   with a pathname components separator ("sep" or "altsep").

   在 3.12 版本发生变更: 增加了 *case_sensitive* 形参。

Path.rglob(pattern, *, case_sensitive=None)

   Glob the given relative *pattern* recursively.  This is like
   calling "Path.glob()" with ""**/"" added in front of the *pattern*,
   where *patterns* are the same as for "fnmatch":

      >>> sorted(Path().rglob("*.py"))
      [PosixPath('build/lib/pathlib.py'),
       PosixPath('docs/conf.py'),
       PosixPath('pathlib.py'),
       PosixPath('setup.py'),
       PosixPath('test_pathlib.py')]

   在默认情况下，或当 *case_sensitive* 关键字参数被设为 "None" 时，该
   方法将使用特定平台的大小写规则匹配路径：通常，在 POSIX 上区分大小写
   ，而在 Windows 上不区分大小写。将 *case_sensitive* 设为 "True" 或
   "False" 可覆盖此行为。

   Raises an auditing event "pathlib.Path.rglob" with arguments
   "self", "pattern".

   在 3.11 版本发生变更: Return only directories if *pattern* ends
   with a pathname components separator ("sep" or "altsep").

   在 3.12 版本发生变更: 增加了 *case_sensitive* 形参。

Path.walk(top_down=True, on_error=None, follow_symlinks=False)

   通过对目录树自上而下或自下而上的遍历来生成其中的文件名。

   对于根位置为 *self* 的目录树中的每个目录（包括 *self* 但不包括 '.'
   和 '..'），该方法会产生一个 3 元组 "(dirpath, dirnames, filenames)"
   。

   *dirpath* 是指向当前正被遍历到的目录的 "Path"，*dirnames* 是由表示
   *dirpath* 中子目录名称的字符串组成的列表 (不包括 "'.'" 和 "'..'")，
   *filenames* 是由表示 *dirpath* 中非目录文件名称的字符串组成的列表。
   要获取 *dirpath* 中文件或目录的完整路径 (以 *self* 开头)，可使用
   "dirpath / name"。 这些列表是否排序取决于具体的文件系统。

   如果可选参数 *top_down* 为（默认的）真值，则会在所有子目录的三元组
   生成之前生成父目录的三元组（目录是自上而下遍历的）。 如果
   *top_down* 为假值，则会在所有子目录的三元组生成之后再生成父目录的三
   元组（目录是是自下而上遍历的）。无论 *top_down* 的值是什么，都会在
   遍历目录及其子目录的三元组之前提取子目录列表。

   当 *top_down* 为真值时，调用者可以就地修改 *dirnames* 列表（例如，
   使用 "del" 或切片赋值），而 "Path.walk()" 将只向名称保留在
   *dirnames* 中的子目录递归。 这可用于减少搜索量，或加入特定的访问顺
   序，甚至是在继续 "Path.walk()" 之前通知 "Path.walk()" 调用者创建或
   重命名的目录的相关信息。 当 *top_down* 为假值时修改 *dirnames* 不会
   影响 "Path.walk()" 的行为，因为在 *dirnames* 被提供给调用者时
   *dirnames* 中的目录已经生成了。

   在默认情况下，来自 "os.scandir()" 的错误将被忽略。 如果指定了可选参
   数 *on_error*，则它应为一个可调用对象；调用它需要传入一个参数，即
   "OSError" 的实例。 该可调用对象能处理错误以继续执行遍历或是重新引发
   错误以停止遍历。 请注意可以通过异常对象的 "filename" 属性来获取文件
   名。

   在默认情况下，"Path.walk()" 不会跟踪符号链接，而是将其添加到
   *filenames* 列表中。 将 *follow_symlinks*设为真值可解析符号链接并根
   据它们的目标将其放入*dirnames* 和 *filenames* 中，从而（在受支持的
   系统上）访问符号链接所指向的目录。

   备注:

     请注意将 *follow_symlinks* 设为真值会在链接指向自身的父目录时导致
     无限递归。 "Path.walk()" 不会跟踪已它访问过的目录。

   备注:

     "Path.walk()" 会假定在执行过程中它所遍历的目录没有被修改。 例如，
     如果 *dirnames* 中的某个目录已被替换为符号链接并且
     *follow_symlinks* 为假值，则 "Path.walk()" 仍会尝试进入该目录。
     为防止出现这种行为，请相应地移除 *dirnames* 中的目录。

   备注:

     与 "os.walk()" 不同，当 *follow_symlinks* 为假值时 "Path.walk()"
     会在 *filenames* 中列出指向目录的符号链接。

   这个例子显示每个目录中所有文件使用的总字节数，忽略其中的
   "__pycache__" 目录:

      from pathlib import Path
      for root, dirs, files in Path("cpython/Lib/concurrent").walk(on_error=print):
        print(
            root,
            "consumes",
            sum((root / file).stat().st_size for file in files),
            "bytes in",
            len(files),
            "non-directory files"
        )
        if '__pycache__' in dirs:
              dirs.remove('__pycache__')

   下一个例子是 "shutil.rmtree()" 的一个简单实现。 由于 "rmdir()" 不允
   许在目录为空之前删除该目录因此自下而上地遍历目录树是至关重要的:

      # Delete everything reachable from the directory "top".
      # CAUTION:  This is dangerous! For example, if top == Path('/'),
      # it could delete all of your files.
      for root, dirs, files in top.walk(top_down=False):
          for name in files:
              (root / name).unlink()
          for name in dirs:
              (root / name).rmdir()

   Added in version 3.12.


创建文件和目录
--------------

Path.touch(mode=0o666, exist_ok=True)

   使用给定的路径创建文件。 如果给出了 *mode*，它将与进程的 "umask" 值
   合并以确定文件模式和访问旗标。 如果文件已存在，则当 *exist_ok* 为真
   值时函数将成功执行（并且其修改时间将更新为当前时间），在其他情况下
   则会引发 "FileExistsError"。

   参见: "open()", "write_text()" 和 "write_bytes()" 方法经常被用来创建文
       件。

Path.mkdir(mode=0o777, parents=False, exist_ok=False)

   使用给定的路径新建目录。 如果给出了 *mode*，它将与进程的 "umask" 值
   合并来决定文件模式和访问旗标。 如果路径已存在，则会引发
   "FileExistsError"。

   如果 *parents* 为真值，任何找不到的父目录都会伴随着此路径被创建；它
   们会以默认权限被创建，而不考虑 *mode* 设置（模仿 POSIX 的 "mkdir
   -p" 命令）。

   如果 *parents* 为假值（默认），则找不到的父级目录会引发
   "FileNotFoundError"。

   如果 *exist_ok* 为 false（默认），则在目标已存在的情况下抛出
   "FileExistsError"。

   如果 *exist_ok* 为真值，则 "FileExistsError" 将不会被引发除非给定的
   路径在文件系统中已存在并且不是目录（与 POSIX "mkdir -p" 命令的行为
   相同）。

   在 3.5 版本发生变更: *exist_ok* 形参被加入。

Path.symlink_to(target, target_is_directory=False)

   使该路径成为一个指向 *target* 的符号连接。

   在 Windows，符号链接可以代表文件或者目录，并且不会动态适应目标。 如
   果目标存在，则将创建相匹配的符号链接类型。 在其他情况下，如果
   *target_is_directory* 为真值则符号链接将创建为目录类型否则将创建为
   文件符号链接。 在非 Windows 平台上，*target_is_directory* 将被忽略
   。

      >>> p = Path('mylink')
      >>> p.symlink_to('setup.py')
      >>> p.resolve()
      PosixPath('/home/antoine/pathlib/setup.py')
      >>> p.stat().st_size
      956
      >>> p.lstat().st_size
      8

   备注:

     参数的顺序（link, target) 和 "os.symlink()" 是相反的。

Path.hardlink_to(target)

   将此路径设为一个指向与 *target* 相同文件的硬链接。

   备注:

     参数顺序 (link, target) 和 "os.link()" 是相反的。

   Added in version 3.10.


Renaming and deleting
---------------------

Path.rename(target)

   Rename this file or directory to the given *target*, and return a
   new "Path" instance pointing to *target*.  On Unix, if *target*
   exists and is a file, it will be replaced silently if the user has
   permission. On Windows, if *target* exists, "FileExistsError" will
   be raised. *target* can be either a string or another path object:

      >>> p = Path('foo')
      >>> p.open('w').write('some text')
      9
      >>> target = Path('bar')
      >>> p.rename(target)
      PosixPath('bar')
      >>> target.open().read()
      'some text'

   The target path may be absolute or relative. Relative paths are
   interpreted relative to the current working directory, *not* the
   directory of the "Path" object.

   它根据 "os.rename()" 实现并给出了同样的保证。

   在 3.8 版本发生变更: Added return value, return the new "Path"
   instance.

Path.replace(target)

   Rename this file or directory to the given *target*, and return a
   new "Path" instance pointing to *target*.  If *target* points to an
   existing file or empty directory, it will be unconditionally
   replaced.

   The target path may be absolute or relative. Relative paths are
   interpreted relative to the current working directory, *not* the
   directory of the "Path" object.

   在 3.8 版本发生变更: Added return value, return the new "Path"
   instance.

Path.unlink(missing_ok=False)

   移除此文件或符号链接。如果路径指向目录，则用 "Path.rmdir()" 代替。

   如果 *missing_ok* 为假值（默认），则如果路径不存在将会引发
   "FileNotFoundError"。

   如果 *missing_ok* 为真值，则 "FileNotFoundError" 异常将被忽略（和
   POSIX "rm -f" 命令的行为相同）。

   在 3.8 版本发生变更: 增加了 *missing_ok* 形参。

Path.rmdir()

   移除此目录。此目录必须为空的。


Permissions and ownership
-------------------------

Path.owner()

   Return the name of the user owning the file.  "KeyError" is raised
   if the file's user identifier (UID) isn't found in the system
   database.

Path.group()

   Return the name of the group owning the file.  "KeyError" is raised
   if the file's group identifier (GID) isn't found in the system
   database.

Path.chmod(mode, *, follow_symlinks=True)

   改变文件模式和权限，和 "os.chmod()" 一样。

   此方法通常会跟随符号链接。 某些 Unix 变种支持改变 symlink 本身的权
   限；在这些平台上你可以添加参数 "follow_symlinks=False"，或者使用
   "lchmod()"。

      >>> p = Path('setup.py')
      >>> p.stat().st_mode
      33277
      >>> p.chmod(0o444)
      >>> p.stat().st_mode
      33060

   在 3.10 版本发生变更: 增加了 *follow_symlinks* 形参。

Path.lchmod(mode)

   就像 "Path.chmod()" 但是如果路径指向符号链接则是修改符号链接的模式
   ，而不是修改符号链接的目标。


Correspondence to tools in the "os" module
==========================================

以下是一个映射了 "os" 与 "PurePath"/"Path" 对应相同的函数的表。

+---------------------------------------+------------------------------------------------+
| "os" 和 "os.path"                     | "pathlib"                                      |
|=======================================|================================================|
| "os.path.dirname()"                   | "PurePath.parent"                              |
+---------------------------------------+------------------------------------------------+
| "os.path.basename()"                  | "PurePath.name"                                |
+---------------------------------------+------------------------------------------------+
| "os.path.splitext()"                  | "PurePath.stem", "PurePath.suffix"             |
+---------------------------------------+------------------------------------------------+
| "os.path.join()"                      | "PurePath.joinpath()"                          |
+---------------------------------------+------------------------------------------------+
| "os.path.isabs()"                     | "PurePath.is_absolute()"                       |
+---------------------------------------+------------------------------------------------+
| "os.path.relpath()"                   | "PurePath.relative_to()" [1]                   |
+---------------------------------------+------------------------------------------------+
| "os.path.expanduser()"                | "Path.expanduser()" [2]                        |
+---------------------------------------+------------------------------------------------+
| "os.path.realpath()"                  | "Path.resolve()"                               |
+---------------------------------------+------------------------------------------------+
| "os.path.abspath()"                   | "Path.absolute()" [3]                          |
+---------------------------------------+------------------------------------------------+
| "os.path.exists()"                    | "Path.exists()"                                |
+---------------------------------------+------------------------------------------------+
| "os.path.isfile()"                    | "Path.is_file()"                               |
+---------------------------------------+------------------------------------------------+
| "os.path.isdir()"                     | "Path.is_dir()"                                |
+---------------------------------------+------------------------------------------------+
| "os.path.islink()"                    | "Path.is_symlink()"                            |
+---------------------------------------+------------------------------------------------+
| "os.path.isjunction()"                | "Path.is_junction()"                           |
+---------------------------------------+------------------------------------------------+
| "os.path.ismount()"                   | "Path.is_mount()"                              |
+---------------------------------------+------------------------------------------------+
| "os.path.samefile()"                  | "Path.samefile()"                              |
+---------------------------------------+------------------------------------------------+
| "os.getcwd()"                         | "Path.cwd()"                                   |
+---------------------------------------+------------------------------------------------+
| "os.stat()"                           | "Path.stat()"                                  |
+---------------------------------------+------------------------------------------------+
| "os.lstat()"                          | "Path.lstat()"                                 |
+---------------------------------------+------------------------------------------------+
| "os.listdir()"                        | "Path.iterdir()"                               |
+---------------------------------------+------------------------------------------------+
| "os.walk()"                           | "Path.walk()" [4]                              |
+---------------------------------------+------------------------------------------------+
| "os.mkdir()", "os.makedirs()"         | "Path.mkdir()"                                 |
+---------------------------------------+------------------------------------------------+
| "os.link()"                           | "Path.hardlink_to()"                           |
+---------------------------------------+------------------------------------------------+
| "os.symlink()"                        | "Path.symlink_to()"                            |
+---------------------------------------+------------------------------------------------+
| "os.readlink()"                       | "Path.readlink()"                              |
+---------------------------------------+------------------------------------------------+
| "os.rename()"                         | "Path.rename()"                                |
+---------------------------------------+------------------------------------------------+
| "os.replace()"                        | "Path.replace()"                               |
+---------------------------------------+------------------------------------------------+
| "os.remove()", "os.unlink()"          | "Path.unlink()"                                |
+---------------------------------------+------------------------------------------------+
| "os.rmdir()"                          | "Path.rmdir()"                                 |
+---------------------------------------+------------------------------------------------+
| "os.chmod()"                          | "Path.chmod()"                                 |
+---------------------------------------+------------------------------------------------+
| "os.lchmod()"                         | "Path.lchmod()"                                |
+---------------------------------------+------------------------------------------------+

-[ 备注 ]-

[1] "os.path.relpath()" calls "abspath()" to make paths absolute and
    remove "".."" parts, whereas "PurePath.relative_to()" is a lexical
    operation that raises "ValueError" when its inputs' anchors differ
    (e.g. if one path is absolute and the other relative.)

[2] "os.path.expanduser()" returns the path unchanged if the home
    directory can't be resolved, whereas "Path.expanduser()" raises
    "RuntimeError".

[3] "os.path.abspath()" removes "".."" components without resolving
    symlinks, which may change the meaning of the path, whereas
    "Path.absolute()" leaves any "".."" components in the path.

[4] "os.walk()" always follows symlinks when categorizing paths into
    *dirnames* and *filenames*, whereas "Path.walk()" categorizes all
    symlinks into *filenames* when *follow_symlinks* is false (the
    default.)
