__setstate__, a generic __getstate__, listiter.__setstate__, (typed) arrays and memoryviews
```python
import collections.abc
from array import array
list_ = [0, 10, 20]
assert [list_[i] for i in range(len(list_))] == [0, 10, 20]
iterator = iter(list_)
assert [next(iterator) for n in range(2)] == [0, 10]
iterator = iter(list_)
assert iterator.__reduce__() == (iter, (list_,), 0)
assert next(iterator) == 0
assert iterator.__reduce__() == (iter, (list_,), 1)
assert next(iterator) == 10
assert iterator.__reduce__() == (iter, (list_,), 2)
iterator.__setstate__(0)
assert iterator.__reduce__() == (iter, (list_,), 0)
assert next(iterator) == 0
assert next(iterator) == 10
assert next(iterator) == 20
assert iterator.__reduce__() == (iter, (list_,), 3)
assert iterator.__reduce__() == (iter, (list_,), len(list_))
try:
next(iterator)
except StopIteration:
pass
assert iterator.__reduce__() == (iter, ([],))
iterator.__setstate__(1)
try:
assert next(iterator) == 10
except StopIteration:
pass
iterator = iter(list_)
iterator.__setstate__(1)
assert next(iterator) == 10
assert iterator.__reduce__() == (iter, (list_,), 2)
try:
[1, 2, 3].__reduce__()
[1, 2, 3].__reduce_ex__(0)
[1, 2, 3].__reduce_ex__(1)
except TypeError as e:
assert e.args[0] == "can't pickle list objects"
[1, 2, 3].__reduce_ex__(2)
def __getstate__(obj):
if (not isinstance(obj, collections.abc.Iterable)
or isinstance(obj, list)):
raise TypeError('__getstate__ only works with iterables', type(obj))
reducefunc = getattr(obj, '__reduce__ex__', False)
reduceoutput = reducefunc(2) if reducefunc else obj.__reduce__()
if len(reduceoutput) < 3:
raise StopIteration # ?
return reduceoutput[2]
iterator = iter(list_)
assert __getstate__(iterator) == 0
next(iterator)
assert __getstate__(iterator) == 1
next(iterator)
assert __getstate__(iterator) == 2
next(iterator)
assert __getstate__(iterator) == 3
try:
next(iterator)
except StopIteration:
pass
try:
__getstate__(iterator)
except StopIteration:
pass
iterator = iter(list_)
assert __getstate__(iterator) == 0
assert next(iterator) == 0
assert __getstate__(iterator) == 1
iterator.__setstate__(0)
assert __getstate__(iterator) == 0
assert next(iterator) == 0
assert __getstate__(iterator) == 1
try:
__getstate__([1, 2, 3])
except TypeError as e:
assert e.args[0] == "__getstate__ only works with iterables"
assert e.args[1] == list, e.args[1] # list_iterator; type(iter(list()))
pass
# arrays must be typed;
# otherwise random access isn't possible
# because skipping ahead or back by n*size requires n calls to size(array[n])
list_ary = array('i', list_)
iterator = iter(list_ary)
assert [next(iterator) for n in range(2)] == [0, 10]
ary_memoryview = memoryview(list_ary)
iterator = iter(ary_memoryview)
assert [next(iterator) for n in range(2)] == [0, 10]
assert ary_memoryview.obj == list_ary
assert ary_memoryview.tolist() == list_
assert ary_memoryview[1] == 10
ary_memoryview[1] = 100
assert ary_memoryview[1] == 100
assert list_ary[1] == 100
assert ary_memoryview[:2].tolist() == [0, 100]
list_ary[1] = 1000
assert ary_memoryview[1] == 1000
assert ary_memoryview[:2].tolist() == [0, 1000]
ary_memoryview.release()
try:
ary_memoryview[:2].tolist()
except ValueError as e:
assert e.args[0] == "operation forbidden on released memoryview object"
list_ = [0, 10, 20]
iterable = iter(list_)
assert next(iterable) == 0
list_.insert(1, 5)
assert next(iterable) == 5
```
-
https://docs.python.org/3/library/pickle.html#object.__setstate__- listiter_setstate:
https://github.com/python/cpython/blob/v3.10.0a1/Objects/listobject.c#L3215-L3229 :
```c
static PyObject *
listiter_setstate(listiterobject *it, PyObject *state)
{
Py_ssize_t index = PyLong_AsSsize_t(state);
if (index == -1 && PyErr_Occurred())
return NULL;
if (it->it_seq != NULL) {
if (index < 0)
index = 0;
else if (index > PyList_GET_SIZE(it->it_seq))
index = PyList_GET_SIZE(it->it_seq); /* iterator exhausted */
it->it_index = index;
}
Py_RETURN_NONE;
}
```c