Skip to content
Merged
10 changes: 10 additions & 0 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5871,6 +5871,16 @@ Frozen dictionaries
:class:`!frozendict` is not a :class:`!dict` subclass but inherits directly
from ``object``.

.. classmethod:: fromkeys(iterable, value=None, /)
Comment thread
corona10 marked this conversation as resolved.
Outdated

Create a new frozen dictionary with keys from *iterable* and values set to
*value*.

:meth:`fromkeys` is a class method that returns a new frozen dictionary.
*value* defaults to ``None``. All of the values refer to just a single
instance, so it generally doesn't make sense for *value* to be a mutable
object such as an empty list.

.. versionadded:: next


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Optimize :meth:`dict.fromkeys` and :meth:`frozendict.fromkeys` to avoid
unnecessary thread-safety operations in frozendict cases. Patch by Donghee
Na.
63 changes: 56 additions & 7 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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)
{
Expand Down Expand Up @@ -3284,15 +3290,23 @@ _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);
d = (PyObject *)dict_dict_fromkeys(mp, iterable, 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;

Expand All @@ -3302,14 +3316,37 @@ _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){
Py_DECREF(d);
return NULL;
}

if (PyAnyDict_CheckExact(d)) {
if (PyDict_CheckExact(d)) {
Comment thread
vstinner marked this conversation as resolved.
Py_BEGIN_CRITICAL_SECTION(d);
while ((key = PyIter_Next(it)) != NULL) {
status = setitem_lock_held((PyDictObject *)d, key, value);
Expand All @@ -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) {
status = anydict_setitem_take2((PyDictObject *)d,
Comment thread
vstinner marked this conversation as resolved.
Py_NewRef(key), Py_NewRef(value));
Comment thread
kumaraditya303 marked this conversation as resolved.
Outdated
Py_DECREF(key);
if (status < 0) {
assert(PyErr_Occurred());
goto Fail;
}
}
}
else {
while ((key = PyIter_Next(it)) != NULL) {
status = PyObject_SetItem(d, key, value);
Py_DECREF(key);
Expand Down
Loading