PEP 234: Iterators
Michael Hudson
mwh21 at cam.ac.uk
Tue May 1 18:15:00 EDT 2001
Just van Rossum <just at letterror.com> writes:
> "Rainer Deyke" <root at rainerdeyke.com> writes:
>
> [ getting an exception when you modify a dict during iteration ]
> > It would be nice if this could be made reliable.
>
> Michael Hudson wrote:
>
> > Tricky, that. It could be made somewhat more reliable, but I think
> > making it totally certain would have prohibitive drawbacks,
> > particularly as stuff like:
> >
> > for i in d:
> > d[i] += 1
> >
> > *is* supported.
>
> I think you get a RuntimeError if the dictionary gets resized: the dict
> iterator object can check cheaply for that event.
Yes.
> Perhaps if the dict object grew a magic counter, which would get
> incremented when a new key is added or a key is deleted, and the
> dict iterator would check for *that* value, this would be more
> reliable.
It's not very hard, as it turns out:
Index: dictobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/dictobject.c,v
retrieving revision 2.81
diff -c -1 -r2.81 dictobject.c
*** dictobject.c 2001/05/01 12:10:21 2.81
--- dictobject.c 2001/05/01 22:12:43
***************
*** 103,104 ****
--- 103,105 ----
int ma_poly; /* appopriate entry from polys vector */
+ int ma_altercount; /* magic to prevent dict mutation on iteration */
dictentry *ma_table;
***************
*** 144,145 ****
--- 145,147 ----
mp->ma_used = 0;
+ mp->ma_altercount = 0;
mp->ma_lookup = lookdict_string;
***************
*** 367,370 ****
else {
! if (ep->me_key == NULL)
mp->ma_fill++;
else
--- 369,374 ----
else {
! if (ep->me_key == NULL) {
mp->ma_fill++;
+ mp->ma_altercount++;
+ }
else
***************
*** 547,548 ****
--- 551,553 ----
goto empty;
+ mp->ma_altercount++;
ep = (mp->ma_lookup)(mp, key, hash);
***************
*** 1481,1483 ****
dictobject *di_dict;
! int di_size;
int di_pos;
--- 1486,1488 ----
dictobject *di_dict;
! int di_altercount;
int di_pos;
***************
*** 1495,1497 ****
di->di_dict = dict;
! di->di_size = dict->ma_size;
di->di_pos = 0;
--- 1500,1502 ----
di->di_dict = dict;
! di->di_altercount = dict->ma_altercount;
di->di_pos = 0;
***************
*** 1513,1517 ****
! if (di->di_size != di->di_dict->ma_size) {
PyErr_SetString(PyExc_RuntimeError,
! "dictionary changed size during iteration");
return NULL;
--- 1518,1522 ----
! if (di->di_altercount != di->di_dict->ma_altercount) {
PyErr_SetString(PyExc_RuntimeError,
! "dictionary altered during iteration");
return NULL;
> I can't judge whether this approach would be too expensive or not.
Me neither. It's at least possible. I could run a pybench run, but
right now I'm going to bed.
see-you-tomorrow-ly y'rs,
M.
--
"The future" has arrived but they forgot to update the docs.
-- R. David Murray, 9 May 2000
More information about the Python-list
mailing list