On Apr 27, 2020, at 13:41, Christopher Barker <python...@gmail.com> wrote:
> 
> SIDE NOTE: this is reminding me that there have been calls in the past for an 
> optional __len__ protocol for iterators that are not proper sequences, but DO 
> know their length -- maybe one more place to use that if it existed.

But __len__ doesn’t really make sense on iterators.

And no iterator is a proper sequence, so I think you meant _iterables_ that 
aren’t proper sequences anyway—and that’s already there:

    xs = {1, 2, 3}
    len(xs) # 3
    isinstance(xs, collections.abc.Sized) # True

I think the issue is that people don’t actually want zip to be an Iterator, 
they want it to be a smarter Iterable that preserves (at least) Sized from its 
inputs. The same way, e.g., dict.items or memoryview does. The same way range 
is lazy but not an Iterator.

And it’s not just zip; the same thing is true for map, enumerate, islice, etc.

And it’s also not just Sized. It would be just as cool if zip, enumerate, etc. 
preserved Reversible. In fact, “how do I both enumerate and reverse” comes up 
often enough that I’ve got a reverse_enumerate function in my toolbox to work 
around it. And, for that matter, why do they have to be only one-shot-iterable 
unless their input is? Again, dict.items and range come to mind, and there’s no 
real reason zip,
map, islice, etc. couldn’t preserve as much of their input behavior as possible:

    xs = [1, 2, 3]
    ys = map(lambda x: x*3, xs)
    len(ys) # 3
    reversed(enumerate(ys))[-1] # (0, 3)

Of course it’s not always possible to preserve all behavior:

    xs = [1, 2, 3]
    ys = filter(lambda x: x%2, xs)
    len(ys) # still a TypeError even though xs is sized

… but the cases where it is or isn’t possible can all be worked out for each 
function and each ABC: filter can _never_ preserve Sized but can _always_ 
preserves Reversible, etc.

This is clearly feasible—Swift does it, and C++ is trying to do it in their 
next version, and Python already does it in a few special cases (as mentioned 
earlier), just not in all (or even most) of the potentially useful cases.

The only really hard part of this is designing a framework that makes it 
possible to write all those views simply. You don’t want to have to write five 
different map view classes for all the ways a map can act based on its inputs, 
and then repeat 80% of that same work again for filter, and again for islice 
and so on. The boilerplate would be insane. (See the Swift 1.0 stdlib for an 
example of how horrible it could be, and they only implemented a handful of the 
possibilities.)

And, except for a couple of things (notably genexprs), most of this could be 
written as a third-party library today. (And if it existed and people were 
using it widely, it would be pretty easy to argue that it should come with 
Python, so that it _could_ handle those last few things like genexprs, and also 
to serve as an example to encourage third-party libraries like toolz to 
similarly implement smart views instead of dumb iterators, and also as helpers 
to make that easier for them. That argument might or might not win the day, but 
at least it’s obvious what it would look like.)

So I suspect the only reason nobody’s done so is that you don’t actually run 
into a need for it very often.

How often do you actually need the result of zip to be Sized anyway?

At least for me, it’s not very often. Whenever I run into any of these needs, I 
start thinking about the fully general solution, but put it off until I run 
into a second good use for it and meanwhile write a simple 2-minute workaround 
for my immediate use (or add a new special case like reversed_enumerate to my 
toolbox), and then by the time I run into another need for it, it’s been so 
long that I’ve almost forgotten the idea…

But maybe there would be a lot more demand for this if people knew the idea was 
feasible? Maybe there are people who have tons of real-life examples where they 
could use a Sized zip or a Reversible enumerate or a Sequence map, and they 
just never thought they could have it so they never tried or asked?

_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/3DAO3ZS7ZF4TIOKJBJK3XANTKNQ6DOKG/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to