https://github.com/python/cpython/commit/16ccdbc50a3034f9c0e5ea6845356281b2ad04bd
commit: 16ccdbc50a3034f9c0e5ea6845356281b2ad04bd
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-02-18T18:03:04+01:00
summary:
gh-141510: Fix frozendict.fromkeys() for dict subclasses (#144962)
Copy also the dictionary if a dict subclass returns a frozendict.
files:
M Lib/test/test_dict.py
M Objects/dictobject.c
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 1a8ae1cd42356e..71f72cb2557670 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -1815,6 +1815,16 @@ class FrozenDictSubclass2(frozendict):
self.assertEqual(fd, frozendict(a=None, b=None, c=None))
self.assertEqual(type(fd), FrozenDictSubclass2)
+ # Dict subclass which overrides the constructor
+ class DictSubclass(dict):
+ def __new__(self):
+ return created
+
+ fd = DictSubclass.fromkeys("abc")
+ self.assertEqual(fd, frozendict(x=1, a=None, b=None, c=None))
+ self.assertEqual(type(fd), DictSubclass)
+ self.assertEqual(created, frozendict(x=1))
+
if __name__ == "__main__":
unittest.main()
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 8d3c34f87e2afe..af3fcca7455470 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -138,6 +138,7 @@ As a consequence of this, split keys have a maximum size of
16.
// Forward declarations
static PyObject* frozendict_new(PyTypeObject *type, PyObject *args,
PyObject *kwds);
+static PyObject* dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static int dict_merge(PyObject *a, PyObject *b, int override);
@@ -3305,15 +3306,18 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable,
PyObject *value)
return NULL;
}
- // If cls is a frozendict subclass with overridden constructor,
+ // If cls is a dict or frozendict subclass with overridden constructor,
// copy the frozendict.
PyTypeObject *cls_type = _PyType_CAST(cls);
- if (PyFrozenDict_Check(d)
- && PyObject_IsSubclass(cls, (PyObject*)&PyFrozenDict_Type)
- && cls_type->tp_new != frozendict_new)
- {
+ if (PyFrozenDict_Check(d) && cls_type->tp_new != frozendict_new) {
// Subclass-friendly copy
- PyObject *copy = frozendict_new(cls_type, NULL, NULL);
+ PyObject *copy;
+ if (PyObject_IsSubclass(cls, (PyObject*)&PyFrozenDict_Type)) {
+ copy = frozendict_new(cls_type, NULL, NULL);
+ }
+ else {
+ copy = dict_new(cls_type, NULL, NULL);
+ }
if (copy == NULL) {
Py_DECREF(d);
return NULL;
_______________________________________________
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]