Why does `slice` have to be unhashable?

Question:

Why doesn’t python make slice hashable? In my simple mind you can simply xor its start, stop, and step and you will have a good hash.

It will be very useful when we want unordered sets of slices.

Asked By: Daniel Chin

||

Answers:

slice objects aren’t hashable because it’s possible for a slice to be made up of mutable (unhashable) objects, such as a list.

slice() doesn’t require that the arguments be integers – any object type is allowed. This is perfectly legal:

slice([1, 2, 3], [4, 5, 6])

though it’s not very useful, since using that slice object for indexing generally won’t work:

>>> s = slice([1,2,3], [4,5,6])
>>> a = [10, 11, 12]
>>> a[s]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: slice indices must be integers or None or have an __index__ method
Answered By: sj95126

It doesn’t have to be, it’s an accident of history. Slices were made comparable back in 2001, but they weren’t made hashable because it caused an issue to do with setting slices as keys in dicts. So no hash method that returns hash(tuple(start, stop, step)) was added, although they’re otherwise treated like a tuple of their start, stop and step values.

Recently this was raised again, considered a bug and fixed. As of version 3.12, this 22 year old problem will finally go away!

For a workaround, you can use this (source) for now, and remove it after everyone is using 3.12 or later:

class hashable_slice:
    """
    Hashable slice wrapper. Can be removed after Python 3.12
    """

    __slots__ = ["slice"]


    def __init__(self, s: slice):
        self.slice = s

    def __hash__(self):
        return hash((self.slice.start, self.slice.stop, self.slice.step))

    def __eq__(self, other):
        return other == self.slice 
Answered By: Gareth Davidson
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.