mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +00:00
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
This commit is contained in:
parent
3e60e0213e
commit
6716254e71
4 changed files with 45 additions and 27 deletions
|
@ -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)
|
||||
|
@ -291,32 +299,10 @@ class PurePath(object):
|
|||
parsed = [sys.intern(x) for x in unfiltered_parsed if x and x != '.']
|
||||
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)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue