Arithmetic sequences in Python

S

Steven Bethard

Gregory said:
Hey guys, this proposal has already been rejected (it is the PEP 204).

No, this is a subtly different proposal. Antoon is proposing *slice*
literals, not *range* literals. Note that "confusion between ranges and
slice syntax" was one of the reasons for rejection of `PEP 204`_. Which
means that if Antoon really wants his proposal to go through, he
probably needs to make sure that slice literals are clearly distinct
from range literals.

... _PEP 204: http://www.python.org/peps/pep-0204.html

STeVe
 
A

Alex Martelli

Tom Anderson said:
Sounds good. More generally, i'd be more than happy to get rid of list
comprehensions, letting people use list(genexp) instead. That would
obviously be a Py3k thing, though.

I fully agree, but the BDFL has already (tentatively, I hope) Pronounced
that the [...] form will stay in Py3K as syntax sugar for list(...). I
find that to be a truly hateful prospect, but that's the prospect:-(.


Alex
 
A

Antoon Pardon

Op 2006-01-17 said:
Just checking your intent here. What should these do?

(2:5) # should give me 2, 3, 4
Yes.

(2:5:-1) # infinite iterator 2, 1, 0, ...?

No it would give nothing, think xrange(2,5,-1)

:)5) # start at -infinity? what does that even mean?

I'm still thinking abouth this. My preffered idea now it
it would be an endless loop returning bottom elements.
:)5:-1) # start at -infinity and go backwards?!!

This would give nothing. The idea is that if the step is negative
the iteration stops when the (hidden) index is equal or smaller
than the stop value. This is true here from the start.
I suspect you should be raising some sort of exception if the start
isn't defined.

That is a possibility too.
 
A

Antoon Pardon

Op 2006-01-17 said:
Hey guys, this proposal has already been rejected (it is the PEP 204).

No it isn't. In my proposal [1, 2:8, 8] would be equivallent to
[1, slice(2,8), 8]. If someone would want the list [1,2,3,4,5,6,7,8]
with this notation, I would propose a flatten function witch would
work with iterators too, so that flat([1, 2:8, 8]) would be the
same as flat([1, range(2,8), 8])

In my view python already has slice literals. You are only limited
in using this literals an index in subscription. I think this is
a rathter pointless limitation and that literal slices could be
very usefull when made into literals and usable as parameters.
 
A

Antoon Pardon

Op 2006-01-18 said:
Op 2006-01-16 said:
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;-)]]

Why don't we give slices more functionality and use them.
These are a number of ideas I had. (These are python3k ideas)

1) Make slices iterables. (No more need for (x)range)

2) Use a bottom and stop variable as default for the start and
stop attribute. top would be a value that is greater than
any other value, bottom would be a value smaller than any
other value.

3) Allow slice notation to be used anywhere a value can be
used.

4) Provide a number of extra operators on slices.
__neg__ (reverses the slice)
__and__ gives the intersection of two slices
__or__ gives the union of two slices

5) Provide sequences with a range (or slice) method.
This would provide an iterator that iterates over
the indexes of the sequences. A slice could be
provided
+5

for i, el in enumerate(sequence):

would become

for i in sequence.range():
el = sequence


That one, i'm not so happy with - i quite like enumerate; it communicates
intention very clearly. I believe enumerate is implemented with iterators,
meaning it's potentially more efficient than your approach, too. And since
enumerate works on iterators, which yours doesn't, you have to keep it
anyway. Still, both would be possible, and it's a matter of taste.
But the advantage is that this would still work when someone subclasses
a list so that it start index is an other number but 0.

It would be possible to patch enumerate to do the right thing in those
situations - it could look for a range method on the enumerand, and if it
found one, use it to generate the indices. Like this:

def enumerate(thing):
if (hasattr(thing, "range")):
indices = thing.range()
else:
indices = itertools.count()
return itertools.izip(indices, thing)


Fine by me. I'm not against enumerate.
Oh, that is nice. Still, you could also extend enumerate to take a range
as an optional second parameter and do this with it. Six of one, half a
dozen of the other, i suppose.

Yes you could probably do so and I'm not against it, I just think that
range would be a better base on which you can build enumerate and other
things than that enumenrate can be a base. e.g. __len__ could be eliminated
and len would be defined as:

def len(seq):
rng = seq.range()
return rng.stop - rng.start
 
A

Antoon Pardon

Op 2006-01-16 said:
Please visit http://www.python.org/peps/pep-0204.html first.

As you can see, PEP 204 was rejected, mostly because of not-so-obvious
syntax. But IMO the idea behind this pep is very nice. So, maybe
there's a reason to adopt slightly modified Haskell's syntax? Something
like

[1,3..10] --> [1,3,5,7,9]
(1,3..10) --> same values as above, but return generator instead of
list
[1..10] --> [1,2,3,4,5,6,7,8,9,10]
(1 ..) --> 'infinite' generator that yield 1,2,3 and so on
(-3,-5 ..) --> 'infinite' generator that yield -3,-5,-7 and so on

So,
1) "[]" means list, "()" means generator
2) the "start" is required, "step" and "end" are optional.

Also, this can be nicely integrated with enumerations (if they will
appear in python). Haskell is also example of such integration.

With some abuse of the language one can already do a number of things
in python2.4 now.

import sys
from types import SliceType

class vslice(object):

def __init__(self, fun):
self.fun = fun

def __getitem__(self, inx):
if not isinstance(inx, tuple):
inx = inx,
return self.fun(*inx)

@vslice
def rnglst(*arg):
lst = []
for el in arg:
if type(el) is SliceType:
start = el.start or 0
stop = el.stop or sys.maxint
step = el.step or 1
if step > 0:
while start < stop:
lst.append(start)
start += step
else:
while start > stop:
lst.append(start)
start += step
else:
lst.append(el)
return lst

rnglst[3,4,5] --> [3, 4, 5]
rnglst[1, 2:8] --> [1, 2, 3, 4, 5, 6, 7]
rnglst[3:9:2, 21:6:-3] --> [3, 5, 7, 21, 18, 15, 12, 9]
 
S

Steven Bethard

Alex said:
Tom Anderson said:
Sounds good. More generally, i'd be more than happy to get rid of list
comprehensions, letting people use list(genexp) instead. That would
obviously be a Py3k thing, though.

I fully agree, but the BDFL has already (tentatively, I hope) Pronounced
that the [...] form will stay in Py3K as syntax sugar for list(...).

Do you have a link for that? I hadn't seen the pronouncement, and
http://wiki.python.org/moin/Python3.0 still lists that as an open issue.
> I find that to be a truly hateful prospect

I'm not sure I find it truly hateful, but definitely unnecessary.
TOOWTDI and all...

STeVe
 
P

Paul Rubin

Steven Bethard said:
I fully agree, but the BDFL has already (tentatively, I hope)
Pronounced
that the [...] form will stay in Py3K as syntax sugar for list(...).
I find that to be a truly hateful prospect

I'm not sure I find it truly hateful, but definitely
unnecessary. TOOWTDI and all...

Well, [...] notation for regular lists (as opposed to list
comprehensions) is also unnecessary since we could use "list((a,b,c))".

Are we -really- after syntax minimalism? And if we are, shouldn't we
just all switch to using Scheme?
 
A

Alex Martelli

Paul Rubin said:
Well, [...] notation for regular lists (as opposed to list
comprehensions) is also unnecessary since we could use "list((a,b,c))".

Indeed, there's no reason list couldn't accept multiple arguments as an
alternative to one sequence argument, just like min and max. This would
make list(a, b, c) work just perfectly.
Are we -really- after syntax minimalism? And if we are, shouldn't we
just all switch to using Scheme?

No, we're not after syntax minimalism (which might justify moving to
Lisp or Scheme) but syntax that's simple and readable. I see no
credibly simple and readable alternative to {a:b, c:d} dictionary
display syntax, for example; dict(((a,b),(c,d))) just wouldn't cut it,
because of the "parentheses overload" (double entendre intended). But
list has no such problem, and there's really no added value of clarity
and readability in [a,b,c] vs list(a,b,c). And don't tell me that the
added value is that brackets "suggest lists", since they're used to
index tuples and dicts just as well;-). So the only reason they may
"suggest lists" is that you're used to that display form in Python, but
there's no real reason to HAVE a display form for lists at all, IMHO.


Alex
 
?

=?iso-8859-1?B?QW5kcuk=?=

Alex said:
Paul Rubin said:
Well, [...] notation for regular lists (as opposed to list
comprehensions) is also unnecessary since we could use "list((a,b,c))".
[snip] ... or should that be list(snip)?
But
list has no such problem, and there's really no added value of clarity
and readability in [a,b,c] vs list(a,b,c). And don't tell me that the
added value is that brackets "suggest lists", since they're used to
index tuples and dicts just as well;-). So the only reason they may
"suggest lists" is that you're used to that display form in Python, but
there's no real reason to HAVE a display form for lists at all, IMHO.

Alex

I'm reading this and thinking "I disagree (?!) with Alex Martelli;
[a,b,c] is so much easier to read and understand than list(a,b,c)"...

And then it dawned on me that, the first time I learned about list
comprehension (a little over a year ago, in A.M.'s Python in a
Nutshell), I had all kinds of trouble getting used to seeing right away
that the square brackets were an indication that a list was created.
At the time, I would have totally agreed that list(a,b,c) is *much*
clearer...
{or expressions like a = list(x for x in range(1)) ...}

*Now*, I prefer [], as I have been "trained" that way... but, thinking
back, and thinking about teaching Python, I'd have to agree with Alex's
point (not that anyone would care about *my* opinion ;-)

André
 
S

Steven D'Aprano

Steven said:
I'm not sure I find it truly hateful, but definitely unnecessary.
TOOWTDI and all...

TOOWTDI Considered Harmful.

There is confusion between "There's Only One Way To Do
It" and "There's One Obvious Way To Do It". The first
is pejorative, harmful if it were true but stupid since
it is never true. There is never only one way to do
anything but the most trivial things. Perhaps there is
only one way to do a null-op, (pass), but that's about it.

Even when people mean One Obvious and not Only One, it
is still harmful because the emphasis is wrong. The
emphasis is on the *restrictive nature* of a language
which merely gives one obvious way of doing things.

The motto from the Zen of Python is far more nuanced
and sensible, although not as snappy:

"There should be one-- and preferably only one
--obvious way to do it."

The emphasis in the Zen is about *enabling* Python to
have at least one (and preferably only one) obvious
ways to do things. The Zen is about making sure that
solutions are obvious in Python; TOOWTDI is about the
paucity of solutions in the language, and I cringe
every time I see it. See the difference?
 
P

Paul Rubin

Well, [...] notation for regular lists (as opposed to list
comprehensions) is also unnecessary since we could use "list((a,b,c))".

Indeed, there's no reason list couldn't accept multiple arguments as an
alternative to one sequence argument, just like min and max. This would
make list(a, b, c) work just perfectly.

What should the output of "print list(1,2,3)" be? Is there a really
good reason to make it different from the input syntax?

What should list(list(1,2,3)) be? Should "list" really work
completely differently depending on whether it has a single arg or
multiple args?

How would you make a one-element list, which we'd currently write as [3]?
Would you have to say list((3,))?
I see no credibly simple and readable alternative to {a:b, c:d}
dictionary display syntax, for example; dict(((a,b),(c,d))) just
wouldn't cut it, because of the "parentheses overload" (double
entendre intended).

dict(a=b,c=d)

I don't really see why keyword arg names have to be identifiers
either. foo(3=4) can pass a **kwargs containing {3:4}.
But list has no such problem, and there's really no added value of
clarity and readability in [a,b,c] vs list(a,b,c).

That's subjective at best. Even Scheme doesn't make you use
extra keywords to write something as fundamental as a list. ;-)
So the only reason they may "suggest lists" is that you're used to
that display form in Python, but there's no real reason to HAVE a
display form for lists at all, IMHO.

Well, what's supposed to happen when you print a list then?
 
A

Alex Martelli

Paul Rubin said:
What should the output of "print list(1,2,3)" be? Is there a really
good reason to make it different from the input syntax?

If we assume that str and repr must keep coinciding for lists (and why
not), no reason -- just like, say, today:
set([1, 2, 3])

input and output could be identical. Do YOU have any good reason why
sets should print out as set(...) and lists should NOT print out as
list(...)? Is 'list' somehow "deeper" than 'set', to deserve a special
display-form syntax which 'set' doesn't get? Or are you enshrining a
historical accident to the level of an erroneously assumed principle?
What should list(list(1,2,3)) be? Should "list" really work
completely differently depending on whether it has a single arg or
multiple args?

It works just fine for max and min, why should list be different?
How would you make a one-element list, which we'd currently write as [3]?
Would you have to say list((3,))?

Yep. I don't particularly like the "mandatory trailing comma" in the
tuple's display form, mind you, but, if it's good enough for tuples, and
good enough for sets (how else would you make a one-element set?), it's
good enough for lists too. If we can find a nicer singleton-form, let's
dict(a=b,c=d)

I don't really see why keyword arg names have to be identifiers
either. foo(3=4) can pass a **kwargs containing {3:4}.

I much prefer the current arrangement where dict(a=b,c=d) means {'a':b,
'c':d} -- it's much more congruent to how named arguments work for every
other case. Would you force us to quote argument names in EVERY
functioncall...?!

But list has no such problem, and there's really no added value of
clarity and readability in [a,b,c] vs list(a,b,c).

That's subjective at best. Even Scheme doesn't make you use
extra keywords to write something as fundamental as a list. ;-)

In Python, a list is no more fundamental than a dict or a set (in maths,
I guess a set IS more fundamental, of course, but Python's not
necessarily congruent to maths). Only tuples deserve special treatment
on semantical grounds (as they're used to pass multiple arguments to
functions or return multiple values for function). Of course "it's
subjective" -- obviously, some people prize conciseness above everything
else (otherwise APL and its successors would have been stillborn),
others prize verbosity (or else Cobol would never have been coinceived);
but Python's "Middle Way" tends to strike a good balance. IMHO, the
balance would be better served by spelling list(1,2,3) rather than
[1,2,3] (but the BDFL disagrees, so my opinion doesn't matter much).

Well, what's supposed to happen when you print a list then?

Just the same as when you print a set: <typename>(<args>).


Alex
 
A

Antoon Pardon

Op 2006-01-19 said:
It works just fine for max and min, why should list be different?

Well IMO it works fine for max and min because people rarely want
the minimum or maximum over a sequence of tuples or lists.

But how would you make the following list: [(1,3)]

As far as I understand that would have to become:

list(((1,3),))

And [[3]] would have to become:

list((list((3,)),))


In my opinion the bracket notation wins the clarity contest
handsdown in this case and IMO these cases occure frequently
enough.
 
P

Paul Rubin

Antoon Pardon said:
And [[3]] would have to become:
list((list((3,)),))
In my opinion the bracket notation wins the clarity contest
handsdown in this case and IMO these cases occure frequently
enough.

I'm convinced now. Until that, I could have gone either way.
 
S

Steven D'Aprano

Alex said:
I much prefer the current arrangement where dict(a=b,c=d) means {'a':b,
'c':d} -- it's much more congruent to how named arguments work for every
other case. Would you force us to quote argument names in EVERY
functioncall...?!


Hmmm... should these two forms give different results?
({0: 1}, {'a': 1})

I feel very uncomfortable about that. Am I alone?
 
K

Kent Johnson

Paul said:
dict(a=b,c=d)

I don't really see why keyword arg names have to be identifiers
either. foo(3=4) can pass a **kwargs containing {3:4}.

The keywords need to be parseable; what would be the keyword form of
{ '3=4, 5=' : 6 }
or
{ '3=4); print "gotcha"; dict(6=' : 7 }
?

Kent
 
H

Hans Nowak

Alex said:
Do YOU have any good reason why
sets should print out as set(...) and lists should NOT print out as
list(...)? Is 'list' somehow "deeper" than 'set', to deserve a special
display-form syntax which 'set' doesn't get? Or are you enshrining a
historical accident to the level of an erroneously assumed principle?

(I haven't been following this thread much, so I can't tell if you're
actually arguing for this change, or that you are just playing devil's
advocate...)

I would have liked to say that lists are a fundamental data type, much
more so than a set... but in reality that seems to be a matter of taste
and priorities. Pascal, for example, has a set literal, but no list
literal; in fact, it doesn't even have a built-in list type.
 
S

Steven Bethard

Steven said:
Steven said:
I'm not sure I find it truly hateful, but definitely unnecessary.
TOOWTDI and all...
[snip]

Even when people mean One Obvious and not Only One, it is still harmful
because the emphasis is wrong. The emphasis is on the *restrictive
nature* of a language which merely gives one obvious way of doing things.

Perhaps just the *perceived* emphasis is wrong? Let me elaborate...

My intent was only to indicate that I don't think we *gain* anything by
having two forms that are quite similar both syntactically and
semantically. Both [...] and list(...) use exactly the same syntax for
the inner expression[1]. Both use parentheses/brackets, so the inner
expression can be broken across multiple lines in the same ways. Both
produce the same result, a list created in the appropriate manner.

So why have both? That's all I meant by TOOWTDI.

FWIW, I've posted my arguments for removing the redundant [...]
expression in Python 3.0 at:

http://wiki.python.org/moin/Python3.0Suggestions#preview

STeVe

[1] Reminder: I'm *not* arguing for list literals to look like
list(...), only for list comprehensions to look that way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,006
Latest member
LauraSkx64

Latest Threads

Top