]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-141510: Optimize {frozen}dict.fromkeys for frozendict (gh-144915)
authorDonghee Na <donghee.na@python.org>
Tue, 17 Feb 2026 21:46:20 +0000 (06:46 +0900)
committerGitHub <noreply@github.com>
Tue, 17 Feb 2026 21:46:20 +0000 (21:46 +0000)
Misc/NEWS.d/next/Core_and_Builtins/2026-02-17-22-27-11.gh-issue-141510.-4yYsf.rst [new file with mode: 0644]
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 (file)
index 0000000..b031fb3
--- /dev/null
@@ -0,0 +1,2 @@
+Optimize :meth:`!frozendict.fromkeys` to avoid unnecessary thread-safety operations
+in frozendict cases. Patch by Donghee Na.
index 7db2e547b54dba20779bd3ece0ae66358f3c6faf..0959e2c78a3289910643c6cf1a3e29195a023ba1 100644 (file)
@@ -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);