example: ``a[start:stop:step]`` or ``a[start:stop, i]``. See
:func:`itertools.islice` for an alternate version that returns an iterator.
+ .. versionchanged:: 3.12
+ Slice objects are now :term:`hashable` (provided :attr:`~slice.start`,
+ :attr:`~slice.stop`, and :attr:`~slice.step` are hashable).
.. function:: sorted(iterable, /, *, key=None, reverse=False)
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(None, 1, 3, 'xy')
- mapping = {1: 'a', 2: 'b', 3: 'c'}
- with self.assertRaises(TypeError):
- _testcapi.sequence_set_slice(mapping, 1, 3, 'xy')
- self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})
-
def test_sequence_del_slice(self):
# Correct case:
data = [1, 2, 3, 4, 5]
_testcapi.sequence_del_slice(None, 1, 3)
mapping = {1: 'a', 2: 'b', 3: 'c'}
- with self.assertRaises(TypeError):
+ with self.assertRaises(KeyError):
_testcapi.sequence_del_slice(mapping, 1, 3)
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})
>>> import builtins
>>> tests = doctest.DocTestFinder().find(builtins)
- >>> 825 < len(tests) < 845 # approximate number of objects with docstrings
+ >>> 830 < len(tests) < 850 # approximate number of objects with docstrings
True
>>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # objects that actually have doctests
self.assertEqual(repr(slice(1, 2, 3)), "slice(1, 2, 3)")
def test_hash(self):
- # Verify clearing of SF bug #800796
- self.assertRaises(TypeError, hash, slice(5))
+ self.assertEqual(hash(slice(5)), slice(5).__hash__())
+ self.assertEqual(hash(slice(1, 2)), slice(1, 2).__hash__())
+ self.assertEqual(hash(slice(1, 2, 3)), slice(1, 2, 3).__hash__())
+ self.assertNotEqual(slice(5), slice(6))
+
+ with self.assertRaises(TypeError):
+ hash(slice(1, 2, []))
+
with self.assertRaises(TypeError):
- slice(5).__hash__()
+ hash(slice(4, {}))
def test_cmp(self):
s1 = slice(1, 2, 3)
--- /dev/null
+Make the slice object hashable.
return 0;
}
+/* code based on tuplehash() of Objects/tupleobject.c */
+#if SIZEOF_PY_UHASH_T > 4
+#define _PyHASH_XXPRIME_1 ((Py_uhash_t)11400714785074694791ULL)
+#define _PyHASH_XXPRIME_2 ((Py_uhash_t)14029467366897019727ULL)
+#define _PyHASH_XXPRIME_5 ((Py_uhash_t)2870177450012600261ULL)
+#define _PyHASH_XXROTATE(x) ((x << 31) | (x >> 33)) /* Rotate left 31 bits */
+#else
+#define _PyHASH_XXPRIME_1 ((Py_uhash_t)2654435761UL)
+#define _PyHASH_XXPRIME_2 ((Py_uhash_t)2246822519UL)
+#define _PyHASH_XXPRIME_5 ((Py_uhash_t)374761393UL)
+#define _PyHASH_XXROTATE(x) ((x << 13) | (x >> 19)) /* Rotate left 13 bits */
+#endif
+
+static Py_hash_t
+slicehash(PySliceObject *v)
+{
+ Py_uhash_t acc = _PyHASH_XXPRIME_5;
+#define _PyHASH_SLICE_PART(com) { \
+ Py_uhash_t lane = PyObject_Hash(v->com); \
+ if(lane == (Py_uhash_t)-1) { \
+ return -1; \
+ } \
+ acc += lane * _PyHASH_XXPRIME_2; \
+ acc = _PyHASH_XXROTATE(acc); \
+ acc *= _PyHASH_XXPRIME_1; \
+}
+ _PyHASH_SLICE_PART(start);
+ _PyHASH_SLICE_PART(stop);
+ _PyHASH_SLICE_PART(step);
+#undef _PyHASH_SLICE_PART
+ if(acc == (Py_uhash_t)-1) {
+ return 1546275796;
+ }
+ return acc;
+}
+
PyTypeObject PySlice_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"slice", /* Name of this type */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- PyObject_HashNotImplemented, /* tp_hash */
+ (hashfunc)slicehash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
/* Hash for tuples. This is a slightly simplified version of the xxHash
non-cryptographic hash:
- - we do not use any parallellism, there is only 1 accumulator.
+ - we do not use any parallelism, there is only 1 accumulator.
- we drop the final mixing since this is just a permutation of the
output space: it does not help against collisions.
- at the end, we mangle the length with a single constant.