diff options
author | Barney Gale <barney.gale@gmail.com> | 2023-03-05 23:50:21 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-05 23:50:21 (GMT) |
commit | 6716254e71eeb4666fd6d1a13857832caad7b19f (patch) | |
tree | f069df2fd49f583efad636c7fc34f483b6d2a5e9 /Lib/pathlib.py | |
parent | 3e60e0213e9d884a2f4cef4df96956c5d4adde0a (diff) | |
download | cpython-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.py | 36 |
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) |