[Python-Dev] Re: d = {}; d[0:1] = 1; d[0:1] = 2; print d[:]

Guido van Rossum guido@digicool.com
Thu, 01 Mar 2001 16:01:52 -0500


(Adding python-dev, keeping python-list)

> Quoth Robin Thomas <robin.thomas@starmedia.net>:
> | Using Python 2.0 on Win32. Am I the only person to be depressed by the 
> | following behavior now that __getitem__ does the work of __getslice__?
> |
> | Python 2.0 (#8, Oct 16 2000, 17:27:58) [MSC 32 bit (Intel)] on win32
> |  >>> d = {}
> |  >>> d[0:1] = 1
> |  >>> d
> | {slice(0, 1, None): 1}
> |
> | And then, for more depression:
> |
> |  >>> d[0:1] = 2
> |  >>> d
> | {slice(0, 1, None): 1, slice(0, 1, None): 2}
> |
> | And then, for extra extra chagrin:
> |
> |  >>> print d[0:1]
> | Traceback (innermost last):
> |    File "<pyshell#11>", line 1, in ?
> |      d[0:1]
> | KeyError: slice(0, 1, None)
> 
> If it helps, you ruined my day.

Mine too. :-)

> | So, questions:
> |
> | 1) Is this behavior considered a bug by the BDFL or the community at large?

I can't speak for the community, but it smells like a bug to me.

> | If so, has a fix been conceived? Am I re-opening a long-resolved issue?

No, and no.

> | 2) If we're still open to proposed solutions, which of the following do you 
> | like:
> |
> |     a) make slices hash and cmp as their 3-tuple (start,stop,step),
> |        so that if I accidentally set a slice object as a key,
> |        I can at least re-set it or get it or del it :)

Good idea.  The SF patch manager is always open.

> |     b) have dict.__setitem__ expressly reject objects of SliceType
> |        as keys, raising your favorite in (TypeError, ValueError)

This is *also* a good idea.

> From: Donn Cave <donn@oz.net>
> 
> I think we might be able to do better.  I hacked in a quick fix
> in ceval.c that looks to me like it has the desired effect without
> closing the door to intentional slice keys (however unlikely.)
[...]
> *** Python/ceval.c.dist Thu Feb  1 14:48:12 2001
> --- Python/ceval.c      Wed Feb 28 21:52:55 2001
> ***************
> *** 3168,3173 ****
> --- 3168,3178 ----
>         /* u[v:w] = x */
>   {
>         int ilow = 0, ihigh = INT_MAX;
> +       if (u->ob_type->tp_as_mapping) {
> +               PyErr_SetString(PyExc_TypeError,
> +                       "dict object doesn't support slice assignment");
> +               return -1;
> +       }
>         if (!_PyEval_SliceIndex(v, &ilow))
>                 return -1;
>         if (!_PyEval_SliceIndex(w, &ihigh))

Alas, this isn't right.  It defeats the purpose completely: the whole
point was that you should be able to write a sequence class that
supports extended slices.  This uses __getitem__ and __setitem__, but
class instances have a nonzero tp_as_mapping pointer too!

--Guido van Rossum (home page: http://www.python.org/~guido/)