Skip to content

Commit ca5e10e

Browse files
committed
pythonGH-104996: Defer joining of pathlib.PurePath() arguments.
Joining of arguments is moved to `_load_parts`, which is called when a normalized path is needed.
1 parent 328422c commit ca5e10e

File tree

2 files changed

+22
-13
lines changed

2 files changed

+22
-13
lines changed

Lib/pathlib.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,9 @@ class PurePath(os.PathLike):
244244
"""
245245

246246
__slots__ = (
247-
# The `_raw_path` slot stores an unnormalized string path. This is set
247+
# The `_raw_paths` slot stores unnormalized string paths. This is set
248248
# in the `__init__()` method.
249-
'_raw_path',
249+
'_raw_paths',
250250

251251
# The `_drv`, `_root` and `_tail_cached` slots store parsed and
252252
# normalized parts of the path. They are set when any of the `drive`,
@@ -299,10 +299,11 @@ def __init__(self, *args):
299299
paths = []
300300
for arg in args:
301301
if isinstance(arg, PurePath):
302-
path = arg._raw_path
303302
if arg._flavour is ntpath and self._flavour is posixpath:
304303
# GH-103631: Convert separators for backwards compatibility.
305-
path = path.replace('\\', '/')
304+
paths.extend(path.replace('\\', '/') for path in arg._raw_paths)
305+
else:
306+
paths.extend(arg._raw_paths)
306307
else:
307308
try:
308309
path = os.fspath(arg)
@@ -313,13 +314,8 @@ def __init__(self, *args):
313314
"argument should be a str or an os.PathLike "
314315
"object where __fspath__ returns a str, "
315316
f"not {type(path).__name__!r}")
316-
paths.append(path)
317-
if len(paths) == 0:
318-
self._raw_path = ''
319-
elif len(paths) == 1:
320-
self._raw_path = paths[0]
321-
else:
322-
self._raw_path = self._flavour.join(*paths)
317+
paths.append(path)
318+
self._raw_paths = paths
323319

324320
def with_segments(self, *pathsegments):
325321
"""Construct a new path object from any number of path-like objects.
@@ -349,7 +345,14 @@ def _parse_path(cls, path):
349345
return drv, root, parsed
350346

351347
def _load_parts(self):
352-
drv, root, tail = self._parse_path(self._raw_path)
348+
paths = self._raw_paths
349+
if len(paths) == 0:
350+
path = ''
351+
elif len(paths) == 1:
352+
path = paths[0]
353+
else:
354+
path = self._flavour.join(*paths)
355+
drv, root, tail = self._parse_path(path)
353356
self._drv = drv
354357
self._root = root
355358
self._tail_cached = tail
@@ -673,7 +676,11 @@ def is_absolute(self):
673676
# ntpath.isabs() is defective - see GH-44626 .
674677
if self._flavour is ntpath:
675678
return bool(self.drive and self.root)
676-
return self._flavour.isabs(self._raw_path)
679+
else:
680+
for path in self._raw_paths:
681+
if self._flavour.isabs(path):
682+
return True
683+
return False
677684

678685
def is_reserved(self):
679686
"""Return True if the path contains one of the special names reserved
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve performance of :class:`pathlib.PurePath` initialisation by
2+
deferring joining of paths when multiple arguments are given.

0 commit comments

Comments
 (0)