https://github.com/python/cpython/commit/d1b541b047e15bb6bddea50a64d71ddb01935e33
commit: d1b541b047e15bb6bddea50a64d71ddb01935e33
branch: main
author: Donghee Na <[email protected]>
committer: corona10 <[email protected]>
date: 2026-02-17T21:46:20Z
summary:
gh-141510: Optimize {frozen}dict.fromkeys for frozendict (gh-144915)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-02-17-22-27-11.gh-issue-141510.-4yYsf.rst
M Objects/dictobject.c
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-17-22-27-11.gh-issue-141510.-4yYsf.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-17-22-27-11.gh-issue-141510.-4yYsf.rst
new file mode 100644
index 00000000000000..b031fb3c75dea7
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-17-22-27-11.gh-issue-141510.-4yYsf.rst
@@ -0,0 +1,2 @@
+Optimize :meth:`!frozendict.fromkeys` to avoid unnecessary thread-safety
operations
+in frozendict cases. Patch by Donghee Na.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 7db2e547b54dba..0959e2c78a3289 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2671,10 +2671,8 @@ _PyDict_LoadBuiltinsFromGlobals(PyObject *globals)
/* Consumes references to key and value */
static int
-setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
+anydict_setitem_take2(PyDictObject *mp, PyObject *key, PyObject *value)
{
- ASSERT_DICT_LOCKED(mp);
-
assert(key);
assert(value);
assert(PyAnyDict_Check(mp));
@@ -2693,6 +2691,14 @@ setitem_take2_lock_held(PyDictObject *mp, PyObject *key,
PyObject *value)
return insertdict(mp, key, hash, value);
}
+/* Consumes references to key and value */
+static int
+setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
+{
+ ASSERT_DICT_LOCKED(mp);
+ return anydict_setitem_take2(mp, key, value);
+}
+
int
_PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
{
@@ -3284,8 +3290,8 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable,
PyObject *value)
return NULL;
- if (PyAnyDict_CheckExact(d)) {
- if (PyAnyDict_CheckExact(iterable)) {
+ if (PyDict_CheckExact(d)) {
+ if (PyDict_CheckExact(iterable)) {
PyDictObject *mp = (PyDictObject *)d;
Py_BEGIN_CRITICAL_SECTION2(d, iterable);
@@ -3293,6 +3299,14 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable,
PyObject *value)
Py_END_CRITICAL_SECTION2();
return d;
}
+ else if (PyFrozenDict_CheckExact(iterable)) {
+ PyDictObject *mp = (PyDictObject *)d;
+
+ Py_BEGIN_CRITICAL_SECTION(d);
+ d = (PyObject *)dict_dict_fromkeys(mp, iterable, value);
+ Py_END_CRITICAL_SECTION();
+ return d;
+ }
else if (PyAnySet_CheckExact(iterable)) {
PyDictObject *mp = (PyDictObject *)d;
@@ -3302,6 +3316,29 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable,
PyObject *value)
return d;
}
}
+ else if (PyFrozenDict_CheckExact(d)) {
+ if (PyDict_CheckExact(iterable)) {
+ PyDictObject *mp = (PyDictObject *)d;
+
+ Py_BEGIN_CRITICAL_SECTION(iterable);
+ d = (PyObject *)dict_dict_fromkeys(mp, iterable, value);
+ Py_END_CRITICAL_SECTION();
+ return d;
+ }
+ else if (PyFrozenDict_CheckExact(iterable)) {
+ PyDictObject *mp = (PyDictObject *)d;
+ d = (PyObject *)dict_dict_fromkeys(mp, iterable, value);
+ return d;
+ }
+ else if (PyAnySet_CheckExact(iterable)) {
+ PyDictObject *mp = (PyDictObject *)d;
+
+ Py_BEGIN_CRITICAL_SECTION(iterable);
+ d = (PyObject *)dict_set_fromkeys(mp, iterable, value);
+ Py_END_CRITICAL_SECTION();
+ return d;
+ }
+ }
it = PyObject_GetIter(iterable);
if (it == NULL){
@@ -3309,7 +3346,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable,
PyObject *value)
return NULL;
}
- if (PyAnyDict_CheckExact(d)) {
+ if (PyDict_CheckExact(d)) {
Py_BEGIN_CRITICAL_SECTION(d);
while ((key = PyIter_Next(it)) != NULL) {
status = setitem_lock_held((PyDictObject *)d, key, value);
@@ -3321,7 +3358,19 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable,
PyObject *value)
}
dict_iter_exit:;
Py_END_CRITICAL_SECTION();
- } else {
+ }
+ else if (PyFrozenDict_CheckExact(d)) {
+ while ((key = PyIter_Next(it)) != NULL) {
+ // anydict_setitem_take2 consumes a reference to key
+ status = anydict_setitem_take2((PyDictObject *)d,
+ key, Py_NewRef(value));
+ if (status < 0) {
+ assert(PyErr_Occurred());
+ goto Fail;
+ }
+ }
+ }
+ else {
while ((key = PyIter_Next(it)) != NULL) {
status = PyObject_SetItem(d, key, value);
Py_DECREF(key);
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]