Skip to content

Commit 99d7ca6

Browse files
committed
gh-141510: Optimize frozendict(frozendict)
Return the same object unmodified if it's exactly the frozendict type.
1 parent d931725 commit 99d7ca6

2 files changed

Lines changed: 47 additions & 8 deletions

File tree

Lib/test/test_dict.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,13 @@ def test_constructor(self):
18291829
with self.assertRaises(TypeError):
18301830
dict.__init__(d, x=1)
18311831

1832+
# Avoid copy if it's frozendict type
1833+
d2 = frozendict(d)
1834+
self.assertIs(d2, d)
1835+
d2 = FrozenDict(d)
1836+
self.assertIsNot(d2, d)
1837+
self.assertEqual(d2, d)
1838+
18321839
def test_copy(self):
18331840
d = frozendict(x=1, y=2)
18341841
d2 = d.copy()

Objects/dictobject.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5169,15 +5169,47 @@ dict_vectorcall(PyObject *type, PyObject * const*args,
51695169
return NULL;
51705170
}
51715171

5172-
PyObject *self;
5173-
if (Py_Is((PyTypeObject*)type, &PyFrozenDict_Type)
5174-
|| PyType_IsSubtype((PyTypeObject*)type, &PyFrozenDict_Type))
5175-
{
5176-
self = frozendict_new(_PyType_CAST(type), NULL, NULL);
5172+
PyObject *self = dict_new(_PyType_CAST(type), NULL, NULL);
5173+
if (self == NULL) {
5174+
return NULL;
51775175
}
5178-
else {
5179-
self = dict_new(_PyType_CAST(type), NULL, NULL);
5176+
if (nargs == 1) {
5177+
if (dict_update_arg(self, args[0]) < 0) {
5178+
Py_DECREF(self);
5179+
return NULL;
5180+
}
5181+
args++;
51805182
}
5183+
if (kwnames != NULL) {
5184+
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwnames); i++) {
5185+
PyObject *key = PyTuple_GET_ITEM(kwnames, i); // borrowed
5186+
if (PyDict_SetItem(self, key, args[i]) < 0) {
5187+
Py_DECREF(self);
5188+
return NULL;
5189+
}
5190+
}
5191+
}
5192+
return self;
5193+
}
5194+
5195+
static PyObject *
5196+
frozendict_vectorcall(PyObject *type, PyObject * const*args,
5197+
size_t nargsf, PyObject *kwnames)
5198+
{
5199+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
5200+
if (!_PyArg_CheckPositional("frozendict", nargs, 0, 1)) {
5201+
return NULL;
5202+
}
5203+
5204+
if (nargs == 1 && kwnames == NULL
5205+
&& PyFrozenDict_CheckExact(args[0])
5206+
&& Py_Is((PyTypeObject*)type, &PyFrozenDict_Type))
5207+
{
5208+
// frozendict(frozendict) returns the same object unmodified
5209+
return Py_NewRef(args[0]);
5210+
}
5211+
5212+
PyObject *self = frozendict_new(_PyType_CAST(type), NULL, NULL);
51815213
if (self == NULL) {
51825214
return NULL;
51835215
}
@@ -8228,6 +8260,6 @@ PyTypeObject PyFrozenDict_Type = {
82288260
.tp_alloc = _PyType_AllocNoTrack,
82298261
.tp_new = frozendict_new,
82308262
.tp_free = PyObject_GC_Del,
8231-
.tp_vectorcall = dict_vectorcall,
8263+
.tp_vectorcall = frozendict_vectorcall,
82328264
.tp_version_tag = _Py_TYPE_VERSION_FROZENDICT,
82338265
};

0 commit comments

Comments
 (0)