Arithmetic sequences in Python

R

Roberto De Almeida

How about this hack:
.... def __getitem__(self, l):
.... start = l[0]
....
.... if isinstance(l[1], types.EllipsisType):
.... step = 1
.... if len(l) > 2:
.... stop = l[2]
.... else:
.... stop = None
.... else:
.... step = l[1] - l[0]
.... if len(l) > 3:
.... stop = l[3]
.... else:
.... stop = None
....
.... for i in xrange(start, stop+1, step):
.... yield i
l = lazy_range()
print [i for i in l[1,3,...,10]] [1, 3, 5, 7, 9]
print [i for i in l[1,...,10]]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 
P

Paul Rubin

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...?!

Ehh, ok. There could be some special marker to evaluate the lhs, but
the present method is fine too.
 
P

Paul Rubin

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?),

If you really want to get rid of container literals, maybe the best
way is with constructor functions whose interfaces are slightly
different from the existing type-coercion functions:

listx(1,2,3) => [1, 2, 3]
listx(3) => [3]
listx(listx(3)) => [[3]]
dictx((a,b), (c,d)) => {a:b, c:d}
setx(a,b,c) => Set((a,b,c))

listx/dictx/setx would be the display forms as well as the constructor forms.
 
T

Tom Anderson

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?),

If you really want to get rid of container literals, maybe the best way
is with constructor functions whose interfaces are slightly different
from the existing type-coercion functions:

listx(1,2,3) => [1, 2, 3]
listx(3) => [3]
listx(listx(3)) => [[3]]
dictx((a,b), (c,d)) => {a:b, c:d}
setx(a,b,c) => Set((a,b,c))

listx/dictx/setx would be the display forms as well as the constructor forms.

Could these even replace the current forms? If you want the equivalent of
list(sometuple), write list(*sometuple). With a bit of cleverness down in
the worky bits, this could be implemented to avoid the apparent overhead
of unpacking and then repacking the tuple. In fact, in general, it would
be nice if code like:

def f(*args):
fondle(args)

foo = (1, 2, 3)
f(*foo)

Would avoid the unpack/repack.

The problem is that you then can't easily do something like:

mytable = ((1, 2, 3), ("a", "b", "c"), (Tone.do, Tone.re, Tone.mi))
mysecondtable = map(list, mytable)

Although that's moderately easy to work around with possibly the most
abstract higher-order-function i've ever written:

def star(f):
def starred_f(args):
return f(*args)
return starred_f

Which lets us write:

mysecondtable = map(star(list), mytable)

While we're here, we should also have the natural complement of star, its
evil mirror universe twin:

def bearded_star(f):
def bearded_starred_f(*args):
return f(args)
return bearded_starred_f

Better names (eg "unpacking" and "packing") would obviously be needed.

tom
 
P

Paul Rubin

Tom Anderson said:
Could these even replace the current forms? If you want the equivalent
of list(sometuple), write list(*sometuple).

The current list function is supposed to be something like a typecast:

list() = []
xlist() = [] # ok

list(list()) = [] # casting a list to a list does nothing
xlist(xlist()) = [[]] # make a new list, not the same

list(xrange(4)) = [0,1,2,3]
xlist(xrange(4)) = [xrange(4)] # not the same

list((1,2)) = [1,2]
xlist((1,2)) = [(1,2)]

etc.
 
T

Tom Anderson

The current list function is supposed to be something like a typecast:

A what?

;-|
list() = []
xlist() = [] # ok

list(list()) = [] # casting a list to a list does nothing
xlist(xlist()) = [[]] # make a new list, not the same

list(xrange(4)) = [0,1,2,3]
xlist(xrange(4)) = [xrange(4)] # not the same

list((1,2)) = [1,2]
xlist((1,2)) = [(1,2)]

True, but so what? Is it that it has to be that way, or is it just that it
happens to be that way now?

tom
 
S

Steve Holden

Paul said:
The current list function is supposed to be something like a typecast:
list() isn't a function, it's a type.
<type 'type'>

I'm not happy about the way the documentation represents types as
functions, as this obscures the whole essence of Python's object
orientation.

list() = []
xlist() = [] # ok

list(list()) = [] # casting a list to a list does nothing
xlist(xlist()) = [[]] # make a new list, not the same

list(xrange(4)) = [0,1,2,3]
xlist(xrange(4)) = [xrange(4)] # not the same

list((1,2)) = [1,2]
xlist((1,2)) = [(1,2)]

etc.

I presume that here "=" means "evaluates to"?

regards
Steve
 
C

Christoph Zwerschke

Alex said:
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?

These are valid points, but they lead me to the opposite conclusion: Why
not let {a,b,c} stand for set([a,b,c])? That would be very intuitive
since it is the mathematical notation already and since it resembles the
notation of dictionaries which are similar to sets.

(This has been probably discussed already. One problem I'm already
seeing is that {} would be ambiguous.)

Anyway, I think the fact that the notation for a set is clumsy is no
good reason to make the notation for a list clumsy as well.

-- Christoph
 
P

Paul Rubin

Steve Holden said:
list() isn't a function, it's a type.

I'm not sure what the distinction is supposed to be. "list" is anyway
callable, and lambda a:list(a) is certainly a function.
xlist((1,2)) = [(1,2)]
etc.

I presume that here "=" means "evaluates to"?

Yeah, although I meant something more informal, like mathematical
equivalence.

Maybe the preferred spellings for the constructors would use capital
letters: List, Dict, Set, instead of listx or xlist or whatever. That
would break the current meaning of Set but I hope not much depends on
that yet.
 
A

Alex Martelli

Paul Rubin said:
I'm not sure what the distinction is supposed to be. "list" is anyway

You can subclass a type, you can check for it with isinstance, etc, all
things you couldn't do if list was still a factory function as in 2.1
and back.


Alex
 
A

Alex Martelli

Christoph Zwerschke said:
These are valid points, but they lead me to the opposite conclusion: Why
not let {a,b,c} stand for set([a,b,c])? That would be very intuitive

As syntax sugar goes, that would be on a par with the current "dict
display" notation, at least.
(This has been probably discussed already. One problem I'm already
seeing is that {} would be ambiguous.)

Yep, using {} for both sets and dicts wouldn't be a good idea. I
suspect most core Python developers think of dicts as more fundamental
than sets, so... (I may disagree, but I just don't care enough about
such syntax sugar to consider even starting a debate about it on
python-dev, particularly knowing it would fail anyway).
Anyway, I think the fact that the notation for a set is clumsy is no
good reason to make the notation for a list clumsy as well.

I don't agree that <typename>(<arguments>) is a clumsy notation, in
general; rather, I consider "clumsy" much of the syntax sugar that is
traditional in Python. For example, making a shallow copy of a list L
with L[:] is what strikes me as clumsy -- list(L) is SO much better.
And I vastly prefer dict(a=1,b=2) over the clumsy {'a':1, 'b':2}.

I suspect I'm unusual in that being deeply familiar with some notation
and perfectly used to it does NOT necessarily make me LIKE that
notation, nor does it make me any less disposed to critical reappraisal
of it -- the brains of most people do appear to equate habit with
appreciation. In the light of my continuous and unceasing critical
reappraisal of Python's syntax choices, I am quite convinced that many
of them are really brilliant -- with the "display forms" of some
built-in types being one area where I find an unusually high density of
non-brilliance, AKA clumsiness. But, that's just me.


Alex
 
C

Christoph Zwerschke

Alex said:
Yep, using {} for both sets and dicts wouldn't be a good idea. I
suspect most core Python developers think of dicts as more fundamental
than sets, so... (I may disagree, but I just don't care enough about
such syntax sugar to consider even starting a debate about it on
python-dev, particularly knowing it would fail anyway).

I'm still not convinced. At least I'd prefer {a,b,c} over any other
proposed solutions (http://wiki.python.org/moin/Python3.0Suggestions)
such as <a,b,c> or |a,b,c|.

You can argue that the notation for sets can be clumsy because they
aren't used so much as lists or dicts, but you can also argue the other
way around that sets aren't used much because the notation is clumsy
(and because they didn't exist from the beginning).

For instance, if sets had a simple notation, they could be used in more
cases, e.g. replace integer masks (see again
http://wiki.python.org/moin/Python3.0Suggestions):

pat = re.compile("some pattern", re.I|re.S|re.X)
would become
pat = re.compile("some pattern", {re.I, re.S, re.X})
I don't agree that <typename>(<arguments>) is a clumsy notation, in
general; rather, I consider "clumsy" much of the syntax sugar that is
traditional in Python.

If you really could write list(a,b,c) instead of list((a,b,c)) I do
somewhat agree.
> For example, making a shallow copy of a list L
with L[:] is what strikes me as clumsy -- list(L) is SO much better.
Certainly.

And I vastly prefer dict(a=1,b=2) over the clumsy {'a':1, 'b':2}.

Ok, but only as long as you have decent keys...
I suspect I'm unusual in that being deeply familiar with some notation
and perfectly used to it does NOT necessarily make me LIKE that
notation, nor does it make me any less disposed to critical reappraisal
of it -- the brains of most people do appear to equate habit with
appreciation. In the light of my continuous and unceasing critical
reappraisal of Python's syntax choices, I am quite convinced that many
of them are really brilliant -- with the "display forms" of some
built-in types being one area where I find an unusually high density of
non-brilliance, AKA clumsiness. But, that's just me.

Ordinary people are lazy. If we have learned something and got
accustomed to it, we don't want to relearn. It is inconvenient. And
there is this attitude: "If I had so much trouble learning a clumsy
notation, why should future generations have it easier."

And in programming languages, you also have the downward compatibility
problem. Having to change all your old programs makes people even more
dislike any thoughts about changes...

-- Christoph
 
S

Steven D'Aprano

I'm not sure what the distinction is supposed to be. "list" is anyway
callable, and lambda a:list(a) is certainly a function.


class Parrot:
def __init__(self):
pass

Parrot is callable. Is it a function?


Types are types, classes are classes, functions are functions.

Admittedly I still confused between the various flavours of functions
(function, bound method, unbound method, class method, static method...)
*wink* but the difference between types and functions is fairly clear.

Just don't ask about the difference between type and class... *wink*
 
B

Bengt Richter

class Parrot:
def __init__(self):
pass

Parrot is callable. Is it a function?
No. It is an object that inherits a __call__ method that makes it callable with a (<args>) source syntax trailer
in a similar way to an object created with a def (which is a function in python convention, and which
also inherits a __call__ method), but the similarity does not make Parrot a function:
... def __init__(self):
... pass
...
(BTW you could have inherited a do-nothing __init__ ;-)
>>> type(Parrot).mro()
>>> type(Parrot).mro()[0].__call__
>>> type(Parrot).mro()[0].__dict__['__call__']
<slot wrapper '__call__' of 'classobj' objects>

Invoked:
>>> type(Parrot).mro()[0].__dict__['__call__'](Parrot)
<__main__.Parrot instance at 0x02EF340C>

Hm, actually that is like calling the im_func of the unbound method of a newstyle class ...
I think maybe actually Parrot() causes
>>> type(Parrot).mro()[0].__dict__['__call__'].__get__(Parrot, type(Parrot))()
<__main__.Parrot instance at 0x02EF398C>

A function is also an object with a __call__ method. E.g., compare above the line with
calling foo (after definition just below) the long way:
>>> def foo(): return 'returned by foo' ...
>>> type(foo).mro()[0].__dict__['__call__'].__get__(foo, type(foo))()
'returned by foo'

Playing with that a little:
>>> type(foo).mro()
>>> type(foo).mro()[0]
>>> type(foo).mro()[0].__call__
>>> type(foo).mro()[0].__call__(foo) 'returned by foo'
>>> foo.__call__
>>> foo.__call__() 'returned by foo'
>>> type(foo).mro()[0].__call__.__get__
>>> type(foo).mro()[0].__call__.__get__(foo, type(foo))
>>> type(foo).mro()[0].__call__.__get__(foo, type(foo))()
'returned by foo'
or 'returned by foo'
Types are types, classes are classes, functions are functions.
classes seem to be classobjs, designed to implement classic class behavior
but using the new machinery to achieve compatible integration.
Admittedly I still confused between the various flavours of functions
(function, bound method, unbound method, class method, static method...)
*wink* but the difference between types and functions is fairly clear.

Just don't ask about the difference between type and class... *wink*
Why not? ;-)

Regards,
Bengt Richter
 

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

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top