Support for index- and slice-based access, assignment and deletion.
To support obj[key] subscription on an exported class, assign your __getitem__, __setitem__ and __delitem__ overloads to one of two families of special slots:
| operation | sequence protocol (adjusted index) | mapping protocol (raw key) |
|---|---|---|
v = obj[i] | methods::seq_getitem_ (= methods::_getitem_) | methods::map_getitem_ |
obj[i] = v | methods::seq_setitem_ (= methods::_setitem_) | methods::map_setitem_ |
del obj[i] | n/a | methods::map_delitem_ |
Assign a getitem(Py_ssize_t) method to methods::_getitem_. Python adjusts negative indices automatically before calling your method, so that obj[-1] will be adjusted to size() - 1. Your method only needs to check bounds, and raise an IndexError if the index is out of range.
Default iteration for x in obj works automatically through this slot.
If your method already throws a std::out_of_range exception for out of bound indices, like std::vector<T>::at, this will be automatically translated to an IndexError in Python.
If the index uses a type other than Py_ssize_t, you may get an OverflowError instead of IndexError if an index doesn't fit the type. In particular, with size_t you will get an OverflowError for negative numbers. To be fully compliant, roll your own bounds checks as above. But if the OverflowError is acceptable, the method shrinks to:
slice arguments can only be received through the mapping protocol, as a Slice parameter. Assign a getslice(Slice) method to methods::map_getitem_.
__getitem__ method on the methods::map_getitem_ slot, Python ignores the methods::seq_getitem_ for subscription. Move the integer overload to methods::map_getitem_ too, but Python will no longer automatically adjust negative indices! Use adjustIndex() to manually adjust the negative indices; as a bonus, it will also raise IndexError for out-of-range indices.Without a __getitem__ on the methods::seq_getitem_ slot, default iteration no longer works. You have two options:
Register a proper __iter__ function. See Python Iterators for more details:
__getitem__ on methods::seq_getitem_. But don't use adjustIndex() for that one: for callers of PySequence_GetItem(obj, index) with index < -len(obj), the index would be adjusted twice, potentially bringing the index in-range while it still should have been out-of-range.Assignment and deletion follow the same rules through methods::map_setitem_ and methods::map_delitem_. Under the hood, they share the same Py_mp_ass_subscript slot, but a __setitem__ overload has key and value parameters, while a __delitem__ overload takes only a key parameter.
Putting it all together:
Classes | |
| struct | lass::python::Slice |
| Helper type to get or return Python slice objects. More... | |
Functions | |
| Py_ssize_t | lass::python::adjustIndex (Py_ssize_t index, Py_ssize_t sequenceLength) |
| Helper to adjust negative sequence indices. | |
| bool | lass::python::adjustIndexEx (Py_ssize_t *index, Py_ssize_t sequenceLength) |
| Helper to adjust negative sequence indices. | |
| LASS_PYTHON_DLL Py_ssize_t lass::python::adjustIndex | ( | Py_ssize_t | index, |
| Py_ssize_t | sequenceLength ) |
Helper to adjust negative sequence indices.
Use adjustIndex() to adjust the raw index argument of functions that are assigned to methods::map_getitem_, methods::map_setitem_, or methods::map_delitem_. Negative indices will be adjusted to start counting from the end of the sequence.
If the adjusted index is out of range of the sequence, a C++ PythonException exception will be thrown, containing a Python IndexError exception.
See Subscript Protocol for more details.
methods::map_* slots: the sequence slots receive already-adjusted indices.| [in] | index | the raw index to be adjusted |
| [in] | sequenceLength | size of the sequence to adjust the index for |
| PythonException | with an IndexError if adjusted index is outside [0, sequenceLength) |
sequenceLength >= 0Definition at line 90 of file subscript.cpp.
References adjustIndexEx(), and lass::python::impl::fetchAndThrowPythonException().
| LASS_PYTHON_DLL bool lass::python::adjustIndexEx | ( | Py_ssize_t * | index, |
| Py_ssize_t | sequenceLength ) |
Helper to adjust negative sequence indices.
Similar to adjustIndex(), but modifies index in-place, and returns false if the adjusted index is out of range.
See Subscript Protocol for more details.
methods::map_* slots: the sequence slots receive already-adjusted indices.| [in,out] | index | pointer to the raw index to be adjusted |
| [in] | sequenceLength | size of the sequence to adjust the index for |
IndexError Python exception will be set.index != nullptr sequenceLength >= 0 *index is unchangedDefinition at line 69 of file subscript.cpp.
Referenced by adjustIndex().