On Wed, Oct 7, 2020 at 2:13 AM Steven D'Aprano <steve@pearwood.info> wrote:
[about `__setstate__`]
(Aside: I'm actually rather surprised that it's exposed as a dunder.)

It's used for pickling. Someone long ago must have complained that list iterators weren't picklable, and we complied.

I'm not sure that either len or next are good precedents? As far as I
can tell, len() does not call `__length_hint__`, and next() only
dispatches to `__next__`.

I just meant that these are examples of a common pattern in Python, of a *function* wrapping a dunder *method*. Your example (`in` -> `__contains__` with a fallback if that doesn't exist) is better because it shows that a fallback is a known pattern; but it isn't exactly a function.

As for the buffering issue, sure, that's a point against those
proposals, but itertools provides a tee function that buffers the
iterator. So "needs a buffer" is not necessarily a knock-down objection
to these features, even for the std lib.

Well, the buffering requires forethought (you can't call go back unless you had the forethought to set up a buffer first) and consumes memory (which iterators are meant to avoid) so the argument against these is much stronger, and different from the argument against advance() -- the latter's presence costs nothing unless you call it.
 
What's the interface? Is this a skip ahead by N steps, or skip directly
to state N? I can imagine uses for both.

Not all iterators remember how often next() was called, so "skip to state N" is not a reasonable API. The only reasonable thing advance(N) can promise is to be equivalent to calling next() N times.
 
Can we skip backwards if the underlying list supports it?

We shouldn't allow this, since it wouldn't work if the input iterator was changed from a list iterator to e.g. a generator.
 
`listiter.__setstate__` supports the second interface. There's no
getstate dunder that I can see. Should there be?

It's called `__reduce__`. These are used for pickling and the state they pass around is supposed to be opaque.
 
Here's a cautionary tale to suggest some caution. [...]

I guess the worst that could happen in our case is that some class used to be implemented on top of a list and at some point changed to a linked list, and the performance of advance(N) changed from O(1) to O(N). But that's not going to happen to Python's fundamental data types (list, tuple, bytes, str, array), since (for better or for worse) they have many other aspects of their API (notably indexing and slicing) that would change from O(1) to O(N) if the implementation changed to something other than an array.

I'm not arguing against this proposal, or for it. I'm just mentioning
some considerations which should be considered :-)

Same here, for sure. Still waiting for that real-world use case... :-)

--
--Guido van Rossum (python.org/~guido)