Skip to content

Commit b3e372b

Browse files
barneygaleGlyphack
authored andcommitted
pythonGH-112361: Speed up pathlib by removing some temporary objects. (python#112362)
Construct only one new list object (using `list.copy()`) when creating a new path object with a modified tail. This slightly speeds up `with_name()` and `with_suffix()`
1 parent 6dad74b commit b3e372b

File tree

3 files changed

+14
-22
lines changed

3 files changed

+14
-22
lines changed

Lib/pathlib.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -400,13 +400,14 @@ def stem(self):
400400

401401
def with_name(self, name):
402402
"""Return a new path with the file name changed."""
403-
if not self.name:
404-
raise ValueError("%r has an empty name" % (self,))
405403
m = self.pathmod
406404
if not name or m.sep in name or (m.altsep and m.altsep in name) or name == '.':
407-
raise ValueError("Invalid name %r" % (name))
408-
return self._from_parsed_parts(self.drive, self.root,
409-
self._tail[:-1] + [name])
405+
raise ValueError(f"Invalid name {name!r}")
406+
tail = self._tail.copy()
407+
if not tail:
408+
raise ValueError(f"{self!r} has an empty name")
409+
tail[-1] = name
410+
return self._from_parsed_parts(self.drive, self.root, tail)
410411

411412
def with_stem(self, stem):
412413
"""Return a new path with the stem changed."""
@@ -417,21 +418,12 @@ def with_suffix(self, suffix):
417418
has no suffix, add given suffix. If the given suffix is an empty
418419
string, remove the suffix from the path.
419420
"""
420-
m = self.pathmod
421-
if m.sep in suffix or m.altsep and m.altsep in suffix:
422-
raise ValueError("Invalid suffix %r" % (suffix,))
423-
if suffix and not suffix.startswith('.') or suffix == '.':
424-
raise ValueError("Invalid suffix %r" % (suffix))
425-
name = self.name
426-
if not name:
427-
raise ValueError("%r has an empty name" % (self,))
428-
old_suffix = self.suffix
429-
if not old_suffix:
430-
name = name + suffix
421+
if not suffix:
422+
return self.with_name(self.stem)
423+
elif suffix.startswith('.') and len(suffix) > 1:
424+
return self.with_name(self.stem + suffix)
431425
else:
432-
name = name[:-len(old_suffix)] + suffix
433-
return self._from_parsed_parts(self.drive, self.root,
434-
self._tail[:-1] + [name])
426+
raise ValueError(f"Invalid suffix {suffix!r}")
435427

436428
def relative_to(self, other, /, *_deprecated, walk_up=False):
437429
"""Return the relative path to another path identified by the passed
@@ -1029,7 +1021,7 @@ def _glob(self, pattern, case_sensitive, follow_symlinks):
10291021
elif not path_pattern._tail:
10301022
raise ValueError("Unacceptable pattern: {!r}".format(pattern))
10311023

1032-
pattern_parts = list(path_pattern._tail)
1024+
pattern_parts = path_pattern._tail.copy()
10331025
if pattern[-1] in (self.pathmod.sep, self.pathmod.altsep):
10341026
# GH-65238: pathlib doesn't preserve trailing slash. Add it back.
10351027
pattern_parts.append('')

Lib/test/test_pathlib.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,8 +575,6 @@ def test_with_suffix_common(self):
575575
self.assertRaises(ValueError, P('a/b').with_suffix, '.c/.d')
576576
self.assertRaises(ValueError, P('a/b').with_suffix, './.d')
577577
self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.')
578-
self.assertRaises(ValueError, P('a/b').with_suffix,
579-
(self.pathmod.sep, 'd'))
580578

581579
def test_relative_to_common(self):
582580
P = self.cls
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed up a small handful of :mod:`pathlib` methods by removing some
2+
temporary objects.

0 commit comments

Comments
 (0)