xrange not hashable - why not?

Isaac To kkto at csis.hku.hk
Sun Jan 25 21:14:48 EST 2004


>>>>> "Andrew" == Andrew MacIntyre <andymac at bullseye.apana.org.au> writes:

    >> why is an xrange object not hashable?

    Andrew> xrange() returns an iterator.  iterators seem universally
    Andrew> unhashable, probably because they can't be deemed "concrete",
    Andrew> though I can't find anything in the 2.3.3 docs about this -
    Andrew> perhaps the relevant PEPs might.

xrange's are hashable in Python 2.3.

    >> I was trying to do something like:
    >> 
    >> comments = { xrange(0, 4): "Few", xrange(4, 10): "Several",
    >> xrange(10, 100): "A lot", xrange(100, sys.maxint): "Can't count
    >> them"} for (k, v) in comments.items(): if n in k: commentaar = v
    >> break

    Andrew> Even if it worked, there's a nasty performance trap in the
    Andrew> sys.maxint case: if the sys.maxint case is the first returned by
    Andrew> the items() method call and n < 100, the "in" will evaluate the
    Andrew> sys.maxint xrange iterator.

I used to think that the code won't work at all.  I think xrange works like
generators.  If that is the case, the state stored within the xrange in the
dict will cause the whole thing to fail if the same range is used the second
time.  E.g.,

>>> def yrange(x,y):
...     ret = x   
...     while ret < y:
...         yield ret
...         ret += 1
... 
>>> for a in yrange(1,5):
...     print a
... 
1
2
3
4
>>> comments = {
...     yrange(0, 4): "Few",
...     yrange(4,10): "Several",
...     yrange(10,100): "A lot",
...     yrange(100, sys.maxint): "Can't count them"}
>>> for (k,v) in comments.items():
...     if 1 in k:
...         print v
...         break
... 
Few
>>> for (k,v) in comments.items():
...     if 1 in k:
...         print v
...         break
... (type interrupt here after waiting for some time)
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
  File "<stdin>", line 5, in yrange
KeyboardInterrupt

But for xrange this is not the case:

>>> comments = {
...     xrange(0, 4): "Few",
...     xrange(4, 10): "Several",
...     xrange(10, 100): "A lot",
...     xrange(100, sys.maxint): "Can't count them"}
>>> for (k,v) in comments.items():
...     if 1 in k:
...         print v
...         break
... 
Few
>>> for (k,v) in comments.items():
...     if 1 in k:
...         print v
...         break
... 
Few

So xrange is not just an iterator.  On the other hand, things like 1000000
in xrange(1,sys.maxint) really needs a long time to compute.  That makes me
wonder how xrange's are actually implemented.

Regards,
Isaac.



More information about the Python-list mailing list