mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
gh-142495: Make defaultdict keep existed value when racing with __missing__ (GH-142668)
This commit is contained in:
parent
47ec96f133
commit
a043407510
3 changed files with 27 additions and 5 deletions
|
|
@ -186,5 +186,23 @@ def test_union(self):
|
|||
with self.assertRaises(TypeError):
|
||||
i |= None
|
||||
|
||||
def test_factory_conflict_with_set_value(self):
|
||||
key = "conflict_test"
|
||||
count = 0
|
||||
|
||||
def default_factory():
|
||||
nonlocal count
|
||||
count += 1
|
||||
local_count = count
|
||||
if count == 1:
|
||||
test_dict[key]
|
||||
return local_count
|
||||
|
||||
test_dict = defaultdict(default_factory)
|
||||
|
||||
self.assertEqual(count, 0)
|
||||
self.assertEqual(test_dict[key], 2)
|
||||
self.assertEqual(count, 2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
:class:`collections.defaultdict` now prioritizes :meth:`~object.__setitem__`
|
||||
when inserting default values from ``default_factory``. This prevents race
|
||||
conditions where a default value would overwrite a value set before
|
||||
``default_factory`` returns.
|
||||
|
|
@ -2231,11 +2231,11 @@ defdict_missing(PyObject *op, PyObject *key)
|
|||
value = _PyObject_CallNoArgs(factory);
|
||||
if (value == NULL)
|
||||
return value;
|
||||
if (PyObject_SetItem(op, key, value) < 0) {
|
||||
Py_DECREF(value);
|
||||
return NULL;
|
||||
}
|
||||
return value;
|
||||
PyObject *result = NULL;
|
||||
(void)PyDict_SetDefaultRef(op, key, value, &result);
|
||||
// 'result' is NULL, or a strong reference to 'value' or 'op[key]'
|
||||
Py_DECREF(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline PyObject*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue