summaryrefslogtreecommitdiffstats
path: root/Lib/pathlib.py
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2023-03-05 23:50:21 (GMT)
committerGitHub <noreply@github.com>2023-03-05 23:50:21 (GMT)
commit6716254e71eeb4666fd6d1a13857832caad7b19f (patch)
treef069df2fd49f583efad636c7fc34f483b6d2a5e9 /Lib/pathlib.py
parent3e60e0213e9d884a2f4cef4df96956c5d4adde0a (diff)
downloadcpython-6716254e71eeb4666fd6d1a13857832caad7b19f.zip
cpython-6716254e71eeb4666fd6d1a13857832caad7b19f.tar.gz
cpython-6716254e71eeb4666fd6d1a13857832caad7b19f.tar.bz2
GH-101362: Optimise PurePath(PurePath(...)) (GH-101667)
The previous `_parse_args()` method pulled the `_parts` out of any supplied `PurePath` objects; these were subsequently joined in `_from_parts()` using `os.path.join()`. This is actually a slower form of joining than calling `fspath()` on the path object, because it doesn't take advantage of the fact that the contents of `_parts` is normalized! This reduces the time taken to run `PurePath("foo", "bar")` by ~20%, and the time taken to run `PurePath(p, "cheese")`, where `p = PurePath("/foo", "bar", "baz")`, by ~40%. Automerge-Triggered-By: GH:AlexWaygood
Diffstat (limited to 'Lib/pathlib.py')
-rw-r--r--Lib/pathlib.py36
1 files changed, 11 insertions, 25 deletions
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index c37ff21..d375529 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -281,6 +281,14 @@ class PurePath(object):
path = cls._flavour.join(*parts)
sep = cls._flavour.sep
altsep = cls._flavour.altsep
+ if isinstance(path, str):
+ # Force-cast str subclasses to str (issue #21127)
+ path = str(path)
+ else:
+ raise TypeError(
+ "argument should be a str or an os.PathLike "
+ "object where __fspath__ returns a str, "
+ f"not {type(path).__name__!r}")
if altsep:
path = path.replace(altsep, sep)
drv, root, rel = cls._flavour.splitroot(path)
@@ -292,31 +300,9 @@ class PurePath(object):
return drv, root, parsed
@classmethod
- def _parse_args(cls, args):
- # This is useful when you don't want to create an instance, just
- # canonicalize some constructor arguments.
- parts = []
- for a in args:
- if isinstance(a, PurePath):
- parts += a._parts
- else:
- a = os.fspath(a)
- if isinstance(a, str):
- # Force-cast str subclasses to str (issue #21127)
- parts.append(str(a))
- else:
- raise TypeError(
- "argument should be a str object or an os.PathLike "
- "object returning str, not %r"
- % type(a))
- return cls._parse_parts(parts)
-
- @classmethod
def _from_parts(cls, args):
- # We need to call _parse_args on the instance, so as to get the
- # right flavour.
self = object.__new__(cls)
- drv, root, parts = self._parse_args(args)
+ drv, root, parts = self._parse_parts(args)
self._drv = drv
self._root = root
self._parts = parts
@@ -575,7 +561,7 @@ class PurePath(object):
anchored).
"""
drv1, root1, parts1 = self._drv, self._root, self._parts
- drv2, root2, parts2 = self._parse_args(args)
+ drv2, root2, parts2 = self._parse_parts(args)
if root2:
if not drv2 and drv1:
return self._from_parsed_parts(drv1, root2, [drv1 + root2] + parts2[1:])
@@ -662,7 +648,7 @@ class PurePath(object):
return True
# Can't subclass os.PathLike from PurePath and keep the constructor
-# optimizations in PurePath._parse_args().
+# optimizations in PurePath.__slots__.
os.PathLike.register(PurePath)