Velocity Reviews > Arithmetic sequences in Python

# Arithmetic sequences in Python

Alex Martelli
Guest
Posts: n/a

 01-16-2006
Paul Rubin <http://(E-Mail Removed)> wrote:

> Steven D'Aprano <(E-Mail Removed)> writes:
> > For finite sequences, your proposal adds nothing new to existing
> > solutions like range and xrange.

>
> Oh come on, [5,4,..0] is much easier to read than range(5,-1,-1).

But not easier than reversed(range(6)) [[the 5 in one of the two
expressions in your sentence has to be an offbyone]]

Alex

Alex Martelli
Guest
Posts: n/a

 01-16-2006
Steven D'Aprano <(E-Mail Removed)> wrote:

> On Mon, 16 Jan 2006 12:51:58 +0100, Xavier Morel wrote:
>
> > For those who'd need the (0..n-1) behavior, Ruby features something that
> > I find quite elegant (if not perfectly obvious at first), (first..last)
> > provides a range from first to last with both boundaries included, but
> > (first...last) (notice the 3 periods)

>
> No, no I didn't.
>
> Sheesh, that just *screams* "Off By One Errors!!!". Python deliberately
> uses a simple, consistent system of indexing from the start to one past
> the end specifically to help prevent signpost errors, and now some folks
> want to undermine that.
>

Agreed. *IF* we truly needed an occasional "up to X *INCLUDED*"
sequence, it should be in a syntax that can't FAIL to be noticed, such
as range(X, endincluded=True).

Alex

Xavier Morel
Guest
Posts: n/a

 01-16-2006
Steven D'Aprano wrote:
> On Mon, 16 Jan 2006 12:51:58 +0100, Xavier Morel wrote:
>
>> For those who'd need the (0..n-1) behavior, Ruby features something that
>> I find quite elegant (if not perfectly obvious at first), (first..last)
>> provides a range from first to last with both boundaries included, but
>> (first...last) (notice the 3 periods)

>
> No, no I didn't.
>
> Sheesh, that just *screams* "Off By One Errors!!!". Python deliberately
> uses a simple, consistent system of indexing from the start to one past
> the end specifically to help prevent signpost errors, and now some folks
> want to undermine that.
>
>
>

Steven, I never said that Python should use this syntax, I merely showed
how it was done in Ruby.

It's nothing more than a ... basis of discussion... not a "I want that
!!ONE" post (if I did, i'd be using Ruby and posting on c.l.r)

(and you didn't what by the way?)

Xavier Morel
Guest
Posts: n/a

 01-16-2006
Steven D'Aprano wrote:
> On Mon, 16 Jan 2006 12:51:58 +0100, Xavier Morel wrote:
>
>> For those who'd need the (0..n-1) behavior, Ruby features something that
>> I find quite elegant (if not perfectly obvious at first), (first..last)
>> provides a range from first to last with both boundaries included, but
>> (first...last) (notice the 3 periods)

>
> No, no I didn't.
>
> Sheesh, that just *screams* "Off By One Errors!!!". Python deliberately
> uses a simple, consistent system of indexing from the start to one past
> the end specifically to help prevent signpost errors, and now some folks
> want to undermine that.
>
>
>

Steven, I never said that Python should use this syntax, I merely showed
how it was done in Ruby.

It's nothing more than a ... basis of discussion... not a "I want that
!!ONE" post (if I did, i'd be using Ruby and posting on c.l.r)

(and you didn't what by the way?)

Ok scratch that, you didn't notice the 3 periods.

Steven D'Aprano
Guest
Posts: n/a

 01-16-2006
On Mon, 16 Jan 2006 02:58:39 -0800, Paul Rubin wrote:

> Steven D'Aprano <(E-Mail Removed)> writes:
>> solutions like range and xrange.

>
> Oh come on, [5,4,..0] is much easier to read than range(5,-1,-1).

Only in isolation, and arguably not even then. Or do you think that Perl
is much easier to read than Python simply because you can write your
programs in fewer characters?

It looks too much like the list [5,4,0], and is easy to make typos:
[5,4,.0] gives you no syntax error but very different results.

The meaning isn't particular clear: is it supposed to be [start, stop,
step] (the natural expectation for those used to Python slices and ranges)
or [start, next, stop]? It is actually the second, but go back to the
original post by Gregory: after giving examples, he still wrongly
described his proposal as having a "step" parameter. There is no step
parameter -- the step is implied, by subtracting start from next. Such
confusion doesn't bode well.

Python indexing deliberately goes to one-past-the-end counting for a
reason: it helps prevent off-by-one signpost errors. This syntax goes
against that decision, and adds one more thing to memorise about Python:
the end index is not included in the list, except for arithmetic
sequences, where it is, sometimes but not necessarily. In [5,6,10] the end
index 10 is included; in [5,7,10] it isn't.

You've picked the most awkward example of range, I admit. But let's look
at a few others:

[0,..9] versus range(10)
[55, ...73] versus range(55, 74)
[1, 3, ..len(mystr)] versus range(1, len(mystr)+1, 2)
[55, 65, 295] versus range(55, 296, 10)

How often do you find yourself knowing the first two terms of a sequence
but not the step size anyway? Is that a common use case?

>> The only added feature this proposal
>> introduces is infinite iterators, and they aren't particularly hard to
>> make:
>>
>> def arithmetic_sequence(start, step=1):
>> yield start
>> while 1:
>> start += step
>> yield start

>
> Well, that would be itertools.count(start, step) but in general a simple
> expression is nicer than 5 lines of code.

I didn't say that my generator was the only way to produce the required
result, I was pointing out how simple it is. Yes, itertools is the way to
go for this sort of thing.

>> If your proposal included support for ranges of characters, I'd be more
>> interested.

>
> There's something to be said for that. Should ['a'..'z'] be a list or a
> string?

It uses [ something ] syntax, so for consistency with lists and list
comprehensions it should be a list.

But a string would be more practical, since list(['a'..'z']) is easier and
more intuitive than ''.join(['a'..'z']). But I'm not sure that it is
*that* much more practical to deserve breaking the reader's expectation.

So I think the best thing would be to create itertools.chars('a', 'z') or
similar, not new syntax.

--
Steven.

Roy Smith
Guest
Posts: n/a

 01-16-2006
Alex Martelli <(E-Mail Removed)> wrote:
>Agreed. *IF* we truly needed an occasional "up to X *INCLUDED*"
>sequence, it should be in a syntax that can't FAIL to be noticed, such
>as range(X, endincluded=True).

for i in (0..x]:
blah

Alex Martelli
Guest
Posts: n/a

 01-16-2006
Roy Smith <(E-Mail Removed)> wrote:

> Alex Martelli <(E-Mail Removed)> wrote:
> >Agreed. *IF* we truly needed an occasional "up to X *INCLUDED*"
> >sequence, it should be in a syntax that can't FAIL to be noticed, such
> >as range(X, endincluded=True).

>
>
> for i in (0..x]:
> blah

The difference between a round parenthesis and a square bracket can
EASILY be overlooked, depending partly on what font you're using.

Alex

Marc 'BlackJack' Rintsch
Guest
Posts: n/a

 01-16-2006
In <dqgpcm\$eah\$(E-Mail Removed)>, Roy Smith wrote:

> Alex Martelli <(E-Mail Removed)> wrote:
>>Agreed. *IF* we truly needed an occasional "up to X *INCLUDED*"
>>sequence, it should be in a syntax that can't FAIL to be noticed, such
>>as range(X, endincluded=True).

>
>
> for i in (0..x]:
> blah

That would break most editors "highlight matching brace" functionality.

Ciao,
Marc 'BlackJack' Rintsch

Szabolcs Nagy
Guest
Posts: n/a

 01-16-2006
i would love to see a nice, clear syntax instead of
for i in xrange(start, stop, step): ...

because xrange is ugly and iteration over int sequences are important.
we don't need a range() alternative ( [0:10] or [0..10] )
(because no one would ever use range() if there were a nice
integer-for-loop)

there was a proposal (http://www.python.org/peps/pep-0284.html):
for start <= i < stop: ...
but in this way you cannot specify the step parameter and it has some
problems when used in list comprehension.

pep 204 like syntax would be:
for i in (start:stop:step): ...
it is much nicer than xrange, but probably it has some inconsistency
with slicing
(eg (:3)=xrange(3), (-3=itertools.count(-3), (:-3)=?, (3::-1)=? )

for i in (start, start+step .. stop): ...
here start written down twice if it's referred by a name (and if start
is a function call it's evaluated twice)
imho without a step it looks nice:
for i in (start .. stop): ...
but a new syntax would be good only if it can entirely replace the old
one (which then can be made deprecated).

Paul Rubin
Guest
Posts: n/a

 01-16-2006
http://www.velocityreviews.com/forums/(E-Mail Removed) (Alex Martelli) writes:
> > Oh come on, [5,4,..0] is much easier to read than range(5,-1,-1).

>
> But not easier than reversed(range(6))

Heh, I like that, and reversed(xrange(6)) appears to do the right
thing too. I didn't know about __reversed__ before.

> [[the 5 in one of the two
> expressions in your sentence has to be an offbyone]]

Are you sure? I could easily be missing something, since it's easy
to be offbyone with this stuff, but when I try it I get:

Python 2.4.1 (#1, May 16 2005, 15:19:29)
[GCC 4.0.0 20050512 (Red Hat 4.0.0-5)] on linux2
>>> range(5,-1,-1)

[5, 4, 3, 2, 1, 0]
>>>

and (skipping the ascii art banner):

Hugs 98: Based on the Haskell 98 standard
Type for help
Hugs.Base> [5,4..0]
[5,4,3,2,1,0]
Hugs.Base>

which is equivalent. (Of course, having to use 6 instead of 5 in
the range(...) version invites an offbyone error).