Repository navigation
Replace module level mutable containers with immutable containers #139003
Description
Activity
- addedperformancePerformance or resource usagePerformance or resource usage
on Sep 16, 2025 - addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Sep 16, 2025 I tried turning all the lists in
_pydatetimeinto tuple, but didnt really get a speedup here:(.wsl-venv) janeric@Jan-Eric-PC:/mnt/d/Programming/Projects/cpython$ python Python 3.15.0a0 (heads/main:c919d02ede, Sep 6 2025, 15:55:27) [GCC 13.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import timeit >>> timeit.timeit("d.ctime()", setup="from _pydatetime import date; d = date.today()") 4.49665271799995 >>> timeit.timeit("d.ctime()", setup="from _pydatetime import date; d = date.today()") 4.522444048000125 >>> timeit.timeit("d.ctime()", setup="from _pydatetime import date; d = date.today()") 4.512530989999959 >>> timeit.timeit("d.ctime()", setup="from _pydatetime import date; d = date.today()") 4.507625565000126 >>> exit (.wsl-venv) janeric@Jan-Eric-PC:/mnt/d/Programming/Projects/cpython$ python Python 3.15.0a0 (heads/main:c919d02ede, Sep 6 2025, 15:55:27) [GCC 13.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import timeit >>> timeit.timeit("d.ctime()", setup="from _pydatetime import date; d = date.today()") 4.494325492999906 >>> timeit.timeit("d.ctime()", setup="from _pydatetime import date; d = date.today()") 4.547055193000006 >>> timeit.timeit("d.ctime()", setup="from _pydatetime import date; d = date.today()") 4.518809389999888 >>> timeit.timeit("d.ctime()", setup="from _pydatetime import date; d = date.today()") 4.655416744999911 >>>First set of runs is with tuples, second is with lists.
Do we have a frozen dict type for "token.EXACT_TOKEN_TYPES"?
Do we have a frozen dict type for "token.EXACT_TOKEN_TYPES"?
Not yet. See for example https://peps.python.org/pep-0603/ or discussions on discuss.python.org
Ok, thats what i thought.
I also just noticed that i didnt test performance in the freethreaded build...
Should i create a benchmark for each module/PR replacing mutables with immutables or is that not necessary?
if not I'd just go through a bunch where the global isnt publically documented and the tests still pass after making them immutable
@JanEricNitschke Thanks for helping out. I am not sure yet whether PRs will be accepted or not, but that will probably determined on a case by case basis. For the
copymodule the PR was accepted as there was a clear performance gain the the attribute in question was not public (and recently added). I would therefore start with the "easy" cases: a set (or list) that is private and is related to functionality where performance would matter. (there are a few suggestions in the OP, but alsourllib.parsemight be worthwhile)Performance impact may be the greatest for sets (in the FT build they use locks, while lists and dicts try to be safe without locks). You can use the ftscalingbench.py to quickly test whether code scales in the free-threading build.
- added a commit that references this issue
on Mar 28, 2026 - added a commit that references this issue
on Mar 30, 2026
There are many module level containers with constants. By replacing the mutable containers with immutable variants (e.g. replace a set with a frozenset or a list with a tuple) we improve performance (especially in the free-threaded build, see for example #138429) and avoid accidental modification of these containers.
The number of module level lists, dicts and sets on current main is:
Script to list all the module level mutable containers
Not all the mutable containers can be replaced by immutable containers. Some of them need to be mutable (e.g.
copyreg.dispatch_table). And some of them are part of the public API and we might not want to change the type only for performance reasons.Example candidates:
_pydatetime._DAYNAMES(would improve performance ofdate.cdate),token.EXACT_TOKEN_TYPES,xml.etree.ElementTree.HTML_EMPTYLinked PRs