<div dir="ltr"><div dir="ltr">To illustrate the distinction that someone (I think Steven D'Aprano) makes, I think these two (modestly tested, but could have flaws) implementations are both sensible for some purposes. Both are equally "obvious," yet they are different:<div><br></div></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><div><font face="monospace, monospace">>>> import sys</font></div></div></div><div><div><font face="monospace, monospace">>>> from itertools import count</font></div></div><div><div><font face="monospace, monospace">>>> class map1(object):</font></div></div><div><div><font face="monospace, monospace">...     def __init__(self, fn, *seqs):</font></div></div><div><div><font face="monospace, monospace">...         try:     # See if there is a length</font></div></div><div><div><font face="monospace, monospace">...             self._len = min(map(len, seqs))</font></div></div><div><div><font face="monospace, monospace">...         except:  # Fallback isn't in any sense accurate, just "large"</font></div></div><div><div><font face="monospace, monospace">...             self._len = sys.maxsize</font></div></div><div><div><font face="monospace, monospace">...         self._fn = fn</font></div></div><div><div><font face="monospace, monospace">...         self._seqs = seqs</font></div></div><div><div><font face="monospace, monospace">...         self._iters = [iter(seq) for seq in seqs]</font></div></div><div><div><font face="monospace, monospace">...     def __iter__(self):</font></div></div><div><div><font face="monospace, monospace">...         return self</font></div></div><div><div><font face="monospace, monospace">...     def __next__(self):</font></div></div><div><div><font face="monospace, monospace">...         args = [next(it) for it in self._iters]</font></div></div><div><div><font face="monospace, monospace">...         return self._fn(*args)</font></div></div><div><div><font face="monospace, monospace">...     def __len__(self):</font></div></div><div><div><font face="monospace, monospace">...         return self._len</font></div></div><div><div><font face="monospace, monospace">...</font></div></div><div><div><font face="monospace, monospace">>>> class map2(map1):</font></div></div><div><div><font face="monospace, monospace">...     def __init__(self, fn, *seqs):</font></div></div><div><div><font face="monospace, monospace">...         super().__init__(fn, *seqs)</font></div></div><div><div><font face="monospace, monospace">...     def __next__(self):</font></div></div><div><div><font face="monospace, monospace">...         self._len -= 1</font></div></div><div><div><font face="monospace, monospace">...         return super().__next__()</font></div></div><div><div><font face="monospace, monospace">...</font></div></div><div><div><font face="monospace, monospace">>>> m1 = map1(add, [1,2,3,4], (5,6,7))</font></div></div><div><div><font face="monospace, monospace">>>> len(m1)</font></div></div><div><div><font face="monospace, monospace">3</font></div></div><div><div><font face="monospace, monospace">>>> next(m1)</font></div></div><div><div><font face="monospace, monospace">6</font></div></div><div><div><font face="monospace, monospace">>>> len(m1)</font></div></div><div><div><font face="monospace, monospace">3</font></div></div><div><div><font face="monospace, monospace">>>> m2 = map2(add, [1,2,3,4], (5,6,7))</font></div></div><div><div><font face="monospace, monospace">>>> len(m2)</font></div></div><div><div><font face="monospace, monospace">3</font></div></div><div><div><font face="monospace, monospace">>>> next(m2)</font></div></div><div><div><font face="monospace, monospace">6</font></div></div><div><div><font face="monospace, monospace">>>> len(m2)</font></div></div><div><div><font face="monospace, monospace">2</font></div></div><div><div><font face="monospace, monospace">>>> m1_inf = map1(lambda x: x, count())</font></div></div><div><div><font face="monospace, monospace">>>> len(m1_inf)</font></div></div><div><div><font face="monospace, monospace">9223372036854775807</font></div></div><div><div><font face="monospace, monospace">>>> next(m1_inf)</font></div></div><div><div><font face="monospace, monospace">0</font></div></div><div><div><font face="monospace, monospace">>>> next(m1_inf)</font></div></div><div><div><font face="monospace, monospace">1</font></div></div><div><font face="monospace, monospace"><br></font></div></blockquote><font face="arial, helvetica, sans-serif">I wasn't sure what to set self._len to where it doesn't make sense.  I thought of None which makes len(mo) raise one exception, or -1 which makes len(mo) raise a different exception.  I just choose an arbitrary "big" value in the above implementation. mo.__length_hint__() is a possibility, but that is specialized, not a way of providing a response to len(mo).</font><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">I don't have to, but I do keep around mo._seqs as a handle to the underlying sequences.  In concept those could be re-inspected for other properties as the user of the classes desired.<br></font><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><font face="monospace, monospace"><br></font></div></blockquote><div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Sat, Dec 1, 2018 at 12:28 PM David Mertz <<a href="mailto:mertz@gnosis.cx">mertz@gnosis.cx</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div>Other than being able to ask len(), are there any advantages to a slightly less opaque map()? Getting the actual result of applying the function to the element is necessarily either eager or lazy, you can't have both.<br><br><div class="gmail_quote"><div dir="ltr">On Sat, Dec 1, 2018, 12:24 PM Steven D'Aprano <<a href="mailto:steve@pearwood.info" target="_blank">steve@pearwood.info</a> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Sat, Dec 01, 2018 at 12:06:23PM -0500, David Mertz wrote:<br>
<br>
> Given that the anti-fix is just as simple and currently available, I don't<br>
> see why we'd want a change:<br>
> <br>
> # map->sequence<br>
> mo = list(mo)<br>
> <br>
> FWIW, I actually do write exactly that code fairly often, it's not hard.<br>
<br>
Sure, but that makes a copy of the original data and means you lose the <br>
benefit of map being lazy.<br>
<br>
Naturally we will always have the ability to call list and eagerly <br>
convert to a sequence, but these proposals are for a way of getting the <br>
advantages of sequence-like behaviour while still keeping the advantages <br>
of laziness.<br>
<br>
With iterators, the only way to get that advantage of laziness is <br>
to give up the ability to query length, random access to items, etc even <br>
when the underlying data is a sequence and that information would have <br>
been readily available. We can, at least sometimes, have the best of <br>
both worlds. Maybe.<br>
<br>
<br>
-- <br>
Steve<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" rel="noreferrer" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div></div></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature">Keeping medicines from the bloodstreams of the sick; food <br>from the bellies of the hungry; books from the hands of the <br>uneducated; technology from the underdeveloped; and putting <br>advocates of freedom in prisons.  Intellectual property is<br>to the 21st century what the slave trade was to the 16th.<br></div></div></div></div>