Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9a23490

Browse files
committed
Issue #14417: Mutating a dict during lookup now restarts the lookup instead of raising a RuntimeError (undoes issue #14205).
1 parent 7feb9f4 commit 9a23490

5 files changed

Lines changed: 15 additions & 23 deletions

File tree

Doc/library/stdtypes.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2210,10 +2210,6 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098:
22102210
See :class:`collections.Counter` for a complete implementation including
22112211
other methods helpful for accumulating and managing tallies.
22122212

2213-
.. versionchanged:: 3.3
2214-
If the dict is modified during the lookup, a :exc:`RuntimeError`
2215-
exception is now raised.
2216-
22172213
.. describe:: d[key] = value
22182214

22192215
Set ``d[key]`` to *value*.

Doc/whatsnew/3.3.rst

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -557,13 +557,6 @@ Some smaller changes made to the core Python language are:
557557

558558
(:issue:`12170`)
559559

560-
* A dict lookup now raises a :exc:`RuntimeError` if the dict is modified during
561-
the lookup. If you implement your own comparison function for objects used
562-
as dict keys and the dict is shared by multiple threads, access to the dict
563-
should be protected by a lock.
564-
565-
(:issue:`14205`)
566-
567560
* New methods have been added to :class:`list` and :class:`bytearray`:
568561
``copy()`` and ``clear()``.
569562

Lib/test/test_dict.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ def test_mutating_iteration(self):
411411
d[i+1] = 1
412412

413413
def test_mutating_lookup(self):
414-
# changing dict during a lookup
414+
# changing dict during a lookup (issue #14417)
415415
class NastyKey:
416416
mutate_dict = None
417417

@@ -433,9 +433,8 @@ def __eq__(self, other):
433433
key2 = NastyKey(2)
434434
d = {key1: 1}
435435
NastyKey.mutate_dict = (d, key1)
436-
with self.assertRaisesRegex(RuntimeError,
437-
'dictionary changed size during lookup'):
438-
d[key2] = 2
436+
d[key2] = 2
437+
self.assertEqual(d, {key2: 2})
439438

440439
def test_repr(self):
441440
d = {}

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.3.0 Alpha 4?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #14417: Mutating a dict during lookup now restarts the lookup instead
14+
of raising a RuntimeError (undoes issue #14205).
15+
1316
- Issue #14738: Speed-up UTF-8 decoding on non-ASCII data. Patch by Serhiy
1417
Storchaka.
1518

Objects/dictobject.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -439,12 +439,15 @@ lookdict(PyDictObject *mp, PyObject *key,
439439
register size_t i;
440440
register size_t perturb;
441441
register PyDictKeyEntry *freeslot;
442-
register size_t mask = DK_MASK(mp->ma_keys);
443-
PyDictKeyEntry *ep0 = &mp->ma_keys->dk_entries[0];
442+
register size_t mask;
443+
PyDictKeyEntry *ep0;
444444
register PyDictKeyEntry *ep;
445445
register int cmp;
446446
PyObject *startkey;
447447

448+
top:
449+
mask = DK_MASK(mp->ma_keys);
450+
ep0 = &mp->ma_keys->dk_entries[0];
448451
i = (size_t)hash & mask;
449452
ep = &ep0[i];
450453
if (ep->me_key == NULL || ep->me_key == key) {
@@ -468,9 +471,8 @@ lookdict(PyDictObject *mp, PyObject *key,
468471
}
469472
}
470473
else {
471-
PyErr_SetString(PyExc_RuntimeError,
472-
"dictionary changed size during lookup");
473-
return NULL;
474+
/* The dict was mutated, restart */
475+
goto top;
474476
}
475477
}
476478
freeslot = NULL;
@@ -510,9 +512,8 @@ lookdict(PyDictObject *mp, PyObject *key,
510512
}
511513
}
512514
else {
513-
PyErr_SetString(PyExc_RuntimeError,
514-
"dictionary changed size during lookup");
515-
return NULL;
515+
/* The dict was mutated, restart */
516+
goto top;
516517
}
517518
}
518519
else if (ep->me_key == dummy && freeslot == NULL)

0 commit comments

Comments
 (0)