From 94ab051082560a088332c10e7208b9b3bf8e6cd4 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 28 Jul 2023 13:36:20 +0900 Subject: [PATCH 1/8] optimize textwrap.indent() --- Lib/textwrap.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 98bedd27ea3a11..387b6e1a7eeaaf 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -476,13 +476,16 @@ def indent(text, prefix, predicate=None): consist solely of whitespace characters. """ if predicate is None: - def predicate(line): - return line.strip() + predicate = str.strip - def prefixed_lines(): - for line in text.splitlines(True): - yield (prefix + line if predicate(line) else line) - return ''.join(prefixed_lines()) + prefixed_lines = [] + for line in text.splitlines(True): + if predicate(line): + prefixed_lines.extend((prefix, line)) + else: + prefixed_lines.append(line) + + return ''.join(prefixed_lines) if __name__ == "__main__": From 8c5896ccf8732e6235bbe59be3b08fc889457495 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 28 Jul 2023 14:56:39 +0900 Subject: [PATCH 2/8] Add NEWS --- .../next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst diff --git a/Misc/NEWS.d/next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst b/Misc/NEWS.d/next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst new file mode 100644 index 00000000000000..9cba325aed6157 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst @@ -0,0 +1,2 @@ +Optimize :func:`textwrap.indent`. It is ~25% faster for large input. Patch +by Inada Naoki. From 6ee731c46d7344bc51b35a985922bc3d28c51c1b Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 28 Jul 2023 16:09:42 +0900 Subject: [PATCH 3/8] Add what's new entry --- Doc/whatsnew/3.13.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 1d5e34dac28a51..6005ff50ebc02e 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -144,7 +144,8 @@ typing Optimizations ============= - +* :func:`textwrap.indent` is now ~25% faster than before for large input. + (Contributed by Inada Naoki in :gh:`107369`.) Deprecated From fad98a201289a8df21603f3acb4a0352b20cc534 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 29 Jul 2023 01:52:19 +0900 Subject: [PATCH 4/8] Use lstrip instead of strip --- Lib/textwrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 387b6e1a7eeaaf..5fa72a87835bdf 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -476,7 +476,7 @@ def indent(text, prefix, predicate=None): consist solely of whitespace characters. """ if predicate is None: - predicate = str.strip + predicate = str.lstrip prefixed_lines = [] for line in text.splitlines(True): From 4c6a46a3804d61bd05474ae4cce262e4e703fb39 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 29 Jul 2023 10:42:28 +0900 Subject: [PATCH 5/8] avoid temporary tuple. --- Lib/textwrap.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 5fa72a87835bdf..2b32b76e59669a 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -481,9 +481,8 @@ def indent(text, prefix, predicate=None): prefixed_lines = [] for line in text.splitlines(True): if predicate(line): - prefixed_lines.extend((prefix, line)) - else: - prefixed_lines.append(line) + prefixed_lines.append(prefix) + prefixed_lines.append(line) return ''.join(prefixed_lines) From 5e6087885cbc589e5b10baef373f584a805c3a7e Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 29 Jul 2023 12:34:28 +0900 Subject: [PATCH 6/8] use str.isspace instead of lstrip --- Lib/textwrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 2b32b76e59669a..9b21b6ba5ca7af 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -476,7 +476,7 @@ def indent(text, prefix, predicate=None): consist solely of whitespace characters. """ if predicate is None: - predicate = str.lstrip + predicate = lambda s: not s.isspace() prefixed_lines = [] for line in text.splitlines(True): From 16e3dbddc92cbcd060ab23d7364ae46cbcdf06e7 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 29 Jul 2023 14:19:35 +0900 Subject: [PATCH 7/8] add comment about splitlines(True) --- Lib/textwrap.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 9b21b6ba5ca7af..7ca393d1c371aa 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -476,6 +476,10 @@ def indent(text, prefix, predicate=None): consist solely of whitespace characters. """ if predicate is None: + # str.splitlines(True) doesn't produce empty string. + # ''.splitlines(True) => [] + # 'foo\n'.splitlines(True) => ['foo\n'] + # So we can use just `not s.isspace()` here. predicate = lambda s: not s.isspace() prefixed_lines = [] From 734fd018ad3cf6b224fb5b7f42bbe1804ae42511 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 29 Jul 2023 14:58:14 +0900 Subject: [PATCH 8/8] 25% -> 30% --- Doc/whatsnew/3.13.rst | 2 +- .../next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 6005ff50ebc02e..25849a5779f494 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -144,7 +144,7 @@ typing Optimizations ============= -* :func:`textwrap.indent` is now ~25% faster than before for large input. +* :func:`textwrap.indent` is now ~30% faster than before for large input. (Contributed by Inada Naoki in :gh:`107369`.) diff --git a/Misc/NEWS.d/next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst b/Misc/NEWS.d/next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst index 9cba325aed6157..76aeab65e90a20 100644 --- a/Misc/NEWS.d/next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst +++ b/Misc/NEWS.d/next/Library/2023-07-28-14-56-35.gh-issue-107369.bvTq8F.rst @@ -1,2 +1,2 @@ -Optimize :func:`textwrap.indent`. It is ~25% faster for large input. Patch +Optimize :func:`textwrap.indent`. It is ~30% faster for large input. Patch by Inada Naoki.