Title: Replace module level mutable containers with immutable containers · Issue #139003 · python/cpython · GitHub
Open Graph Title: Replace module level mutable containers with immutable containers · Issue #139003 · python/cpython
X Title: Replace module level mutable containers with immutable containers · Issue #139003 · python/cpython
Description: 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...
Open Graph Description: 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 performanc...
X Description: 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 performanc...
Opengraph URL: https://github.com/python/cpython/issues/139003
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Replace module level mutable containers with immutable containers","articleBody":"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 https://github.com/python/cpython/pull/138429) and avoid accidental modification of these containers.\n\nThe number of module level lists, dicts and sets on current main is:\n```\nnumber of mutable module level containers by type:\n\u003cclass 'dict'\u003e: 266\n\u003cclass 'list'\u003e: 150\n\u003cclass 'set'\u003e: 63\n\u003cclass 'collections.defaultdict'\u003e: 2\n\u003cclass '_strptime.TimeRE'\u003e: 1\n\u003cclass 'email._encoded_words._QByteMap'\u003e: 1\n```\n\n\u003cdetails\u003e\u003csummary\u003eScript to list all the module level mutable containers\u003c/summary\u003e\n\n```\nimport sys\nimport importlib\nimport pkgutil\nfrom collections import Counter\n\nblacklist = ('idlelib.idle')\nexcluded_submodule_names = ('__main__')\nsearch_submodules = 2\nmutable_containers = (list, dict, set)\n\ndef list_container_types(module, mcc):\n print_module = False\n for a in dir(module):\n if a in ('__all__', '__path__', '__builtins__', '__annotations__', '__conditional_annotations__'):\n # why is __all__ a list and not a tuple?\n continue\n # if not a.startswith('_'):\n # continue\n attr = getattr(module, a)\n tp = type(attr)\n if issubclass(tp, mutable_containers):\n if not print_module:\n print(f'{module}:')\n print_module = True\n print(f' {a}: {tp}')\n mcc.update([tp])\n\n\ndef search_modules(module_names, search_submodules: int, mcc):\n for name in module_names:\n if name in blacklist:\n continue\n try:\n module = importlib.import_module(name)\n except:\n print(f'{name}: error on import')\n module = None\n list_container_types(module, mcc)\n\n if search_submodules:\n try:\n sub_names = list(z.name for z in pkgutil.iter_modules(module.__path__))\n except Exception as ex:\n sub_names = []\n mm = [name + '.' + sub_name for sub_name in sub_names if sub_name not in excluded_submodule_names]\n search_modules(mm, search_submodules - 1, mcc)\n\nmcc = Counter()\nmodule_names = sorted(list(sys.builtin_module_names)) + sorted(list(sys.stdlib_module_names))\nsearch_modules(module_names, search_submodules=2, mcc = mcc)\n\nprint()\nprint('number of module level containers by type:')\nfor key, value in mcc.items():\n print(f'{key}: {value}')\n```\n\n\u003c/details\u003e\n\nNot 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.\n\nExample candidates: `_pydatetime._DAYNAMES` (would improve performance of `date.cdate`), `token.EXACT_TOKEN_TYPES`, `xml.etree.ElementTree.HTML_EMPTY`\n\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-139004\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/eendebakpt","@type":"Person","name":"eendebakpt"},"datePublished":"2025-09-16T19:58:55.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":5},"url":"https://github.com/139003/cpython/issues/139003"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:0f0abc03-f88b-b778-8e1c-09fc78bac8bc |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | A6AA:258BE8:26DE3D1:3344B28:696B2147 |
| html-safe-nonce | 76c6a3f45fdd0eaa57bbaf177228dc0485bea34b91baba2bb254d347cd76fadd |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBNkFBOjI1OEJFODoyNkRFM0QxOjMzNDRCMjg6Njk2QjIxNDciLCJ2aXNpdG9yX2lkIjoiNzYwNTQ5MDgwNDkxNDMzMTk3NSIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 21fe8d1782e4a7b6bcb1fedcb238dfd244ed06778619f8ab869c6c15876e470d |
| hovercard-subject-tag | issue:3423575403 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/139003/issue_layout |
| twitter:image | https://opengraph.githubassets.com/c3c0635bc3205dc34bed1b4c6fe6a62ef7f82d873e1cbda9b087a3d163ce7e93/python/cpython/issues/139003 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/c3c0635bc3205dc34bed1b4c6fe6a62ef7f82d873e1cbda9b087a3d163ce7e93/python/cpython/issues/139003 |
| og:image:alt | 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 performanc... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | eendebakpt |
| hostname | github.com |
| expected-hostname | github.com |
| None | 5f99f7c1d70f01da5b93e5ca90303359738944d8ab470e396496262c66e60b8d |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 82560a55c6b2054555076f46e683151ee28a19bc |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width