<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Jan 9, 2015 at 11:03 PM, Andrew Barnert <span dir="ltr"><<a href="mailto:abarnert@yahoo.com.dmarc.invalid" target="_blank">abarnert@yahoo.com.dmarc.invalid</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span class=""><div>On Jan 9, 2015, at 21:13, Guido van Rossum <<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>> wrote:</div><div><br></div><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Jan 9, 2015 at 7:29 PM, Andrew Barnert <span dir="ltr"><<a href="mailto:abarnert@yahoo.com.dmarc.invalid" target="_blank">abarnert@yahoo.com.dmarc.invalid</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span>On Jan 9, 2015, at 14:36, Guido van Rossum <<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>> wrote:<br>
<br>
> (Although the actual signature of linspace gives me a headache. :-)<br>
<br>
</span>I'm assuming you're not talking about the rested and dtype args (which the stdlib wouldn't need), but rather the fact that endpoint changes the meaning of num (you effectively generate num+1 points and discard the last, instead of generating num points).<br></blockquote><div><br></div><div>All of the above, plus the default to n=50. :-)<br></div></div></div></div></div></blockquote><div><br></div></span><div>Oh yeah, that too. I see that you fixed that by just not having a default on count, which seems like the best answer.</div><div><br></div><div>So, assuming we can get rid of endpoint (either my way or a better way) are you happy with the signature now?</div></div></blockquote><div><br></div><div>No, the name still blows, we don't know which module to put it in, and there's the discussion about how many values to return.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span class=""><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Oh, and the name is odd-sounding for someone not from your world.<br></div></div></div></div></div></blockquote><div><br></div></span><div>I move around from world to world; it's weird to me whenever I come back to numpy, unless I also need logspace...</div><span class=""><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra">I'm guessing that in terms of implementation you might start with this:<br><br> def linspace(start, stop, num):<br> return [(stop*i + start*(num-i)) / num for i in range(num+1)]<br></div></div></blockquote><div><br></div></span><div>That gives a closed range of num+1 values. I think you want a closed range of num values (or maybe a half-open range of the first num of num+1 values). So you want to replace every num with num-1.</div></div></blockquote><div><br></div><div>Not really. I think of this as splitting the range into `num` equal subranges and returning all the points including the endpoints. I think it would look really weird if you wanted to split [0, 1] into 10 equal sections (or 0.1 each) and you had to say 11.<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span class=""><div><br></div><blockquote type="cite"><div dir="ltr"><div class="gmail_extra">and then refine as follows:<br><br></div><div class="gmail_extra">- make it a lazy sequence, with slicing ability, etc.<br></div></div></blockquote><div><br></div></span><div>If you don't need O(1) __contains__ and friends (and I don't think you do) that's maybe 5 lines of code with the ABC.</div></div></blockquote><div><br></div><div>If it's in the stdlib it should be modeled after range(), which is significantly more sophisticated.<br><br></div><div>OTOH if it's just a one-liner recipe in the docs returning a list is fine.<br><br></div><div>OT3H __contains__ seems a really bad idea, due to general issues with float equality.<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span class=""><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra">- numeric tricks to avoid intermediate overflows or numeric instabilities, plus optimizations<br></div></div></blockquote><div><br></div></span><div>I'll leave this to others. (If no one steps up, I can look at the numpy code, but I'm sure this list has people who know it off the top of their heads.)</div><span class=""><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra">- while still returning exactly the endpoints at the extremes(*)<br></div></div></blockquote><div><br></div></span><div>Likewise.</div><span class=""><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra">- and better error checking (num must be an integer > 0)<br></div></div></blockquote><div><br></div></span><div>Is there anything else that needs to be checked? In particular, start and stop have to be something that can be multiplier and divided by integers, and added to itself, but that's all kinds of types (numbers, numpy arrays of numbers, timedeltas, etc.), so I'm not sure you want to precheck anything there.</div></div></blockquote><div><br></div><div>Fair enough.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span class=""><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra">- and support for start/stop being other numeric types (e.g. complex, Fraction, Decimal)<br></div></div></blockquote><div><br></div></span>That already works out of the box for your implementation, and for the obvious conversion to a lazy sequence. <br><div><br></div><div>It won't work with datetimes because you can't multiply those by integers (you'd need to switch to the naive implementation for those), but it will work with timedeltas and all kinds of other types you'd expect to work.</div><div><br></div><div>In fact, rather than just say how easy it is, give me 10 minutes to code it...</div><div><br></div><div><a href="https://github.com/abarnert/linspace" target="_blank">https://github.com/abarnert/linspace</a></div></div></blockquote><div><br></div><div>I just see more opportunity for bikeshedding. :-(<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span class=""><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra">Then bikeshed about the module it should live in. At least you can shut down the bikeshed about the name with "that's what numpy calls it", and ditto about the argument order. Just don't add any of the other features of the numpy version. :-)<br></div><div class="gmail_extra"><br></div><div class="gmail_extra">(*) I was going to give the equally naive definition [start + i*step for i in range(num+1)] where step is (stop-start)/num, but that would give away my naiveté even quicker. :-)<br></div></div></blockquote></span></div></blockquote></div>Honestly, I think this is better off as a set of recipies (starting with the most naive of all and then discussing various refinements for better accuracy or speed or support of e.g. datetime), with a hefty section on the off-by-one issue, rather than a stdlib function.<br clear="all"></div><div class="gmail_extra"><br>-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido">python.org/~guido</a>)</div>
</div></div>