For loop extended syntax

G

George Sakkis

I'm sure there must have been a past thread about this topic but I don't know how to find it: How
about extending the "for <X> in" syntax so that X can include default arguments ? This would be very
useful for list/generator comprehensions, for example being able to write something like:

[x*y-z for (x,y,z=0) in (1,2,3), (4,5), (6,7,8)]

instead of the less elegant explicit loop version that has to check for the length of each sequence.
What do you think ?

George
 
K

Kay Schluehr

George said:
This would be very
useful for list/generator comprehensions, for example being able to write something like:

[x*y-z for (x,y,z=0) in (1,2,3), (4,5), (6,7,8)]

Looks very appealing, but what to do with

[x*y-z for (x=0,y,z) in (1,2,3), (4,5), (6,7,8)] ?

Should it raise an exception due to a pattern mismatch?

If not how should matching rules apply here?

[x*y-z for (x=0,y=0,z=0) in (1,2,3), (4,5), (6,7,8)]

If in doubt write a vector class that cares about the correct padding (
or more general and with geometric meaning: select the right hyperplane
) and enable to switch between different paddings. This solution is
both flexible and reusable.

Regards Kay
 
M

Matteo Dell'Amico

George said:
I'm sure there must have been a past thread about this topic but I don't know how to find it: How
about extending the "for <X> in" syntax so that X can include default arguments ? This would be very
useful for list/generator comprehensions, for example being able to write something like:

[x*y-z for (x,y,z=0) in (1,2,3), (4,5), (6,7,8)]

instead of the less elegant explicit loop version that has to check for the length of each sequence.
What do you think ?

How did you get the data in that format in the first place? It looks a
bit strange to me. Wouldn't it be easier to fill in default values when
you gather data as opposed to when you use it?
 
G

George Sakkis

Kay Schluehr said:
George said:
This would be very
useful for list/generator comprehensions, for example being able to write something like:

[x*y-z for (x,y,z=0) in (1,2,3), (4,5), (6,7,8)]

Looks very appealing, but what to do with

[x*y-z for (x=0,y,z) in (1,2,3), (4,5), (6,7,8)] ?

Should it raise an exception due to a pattern mismatch?

I didn't have in mind to generalize the syntax even more than the respective for function
signatures, therefore this would be syntax error:
SyntaxError: non-keyword arg after keyword arg
If not how should matching rules apply here?

[x*y-z for (x=0,y=0,z=0) in (1,2,3), (4,5), (6,7,8)]

If in doubt write a vector class that cares about the correct padding (
or more general and with geometric meaning: select the right hyperplane
) and enable to switch between different paddings. This solution is
both flexible and reusable.

Regards Kay

This was just an example; I think the proposed functionality will be helpful in far more cases than
dealing with geometry or vectors, so I would prefer it to be supported by the language itself.

Regards,
George
 
G

George Sakkis

Matteo Dell'Amico said:
George said:
I'm sure there must have been a past thread about this topic but I don't know how to find it: How
about extending the "for <X> in" syntax so that X can include default arguments ? This would be very
useful for list/generator comprehensions, for example being able to write something like:

[x*y-z for (x,y,z=0) in (1,2,3), (4,5), (6,7,8)]

instead of the less elegant explicit loop version that has to check for the length of each sequence.
What do you think ?

How did you get the data in that format in the first place? It looks a
bit strange to me. Wouldn't it be easier to fill in default values when
you gather data as opposed to when you use it?

Not always. Say for example that you're doing some 2D geometry stuff, and later you have to extend
it to 3D. In this case you may have to deal with both 2D and 3D objects, and map the former to the
latter when necessary.

George
 
H

Heiko Wundram

Not always. Say for example that you're doing some 2D geometry stuff, and
later you have to extend it to 3D. In this case you may have to deal with
both 2D and 3D objects, and map the former to the latter when necessary.

But this rather sounds like you'd want an adaptor iterator, like the
following:
... def __init__(self,data):
... self.data = data
... def __iter__(self):
... for item in self.data:
... if len(item) == 2:
... yield item+(0,)
... else:
... yield item
...
for x,y,z in AdaptPossible2D([(1,2),(1,2,3),(3,4)]):
... print x,y,z
...
1 2 0
1 2 3
3 4 0

Using the above code makes it absolutely clear what you want, and doesn't need
any new syntax which can be ambiguous like (x=0,y,z=0), etc. The above idiom
also takes only constant extra space, as it doesn't duplicate the list during
iteration.

--
--- Heiko.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQBCPeapf0bpgh6uVAMRApwVAJ4hFU9cpP74rz4bBqzG4hc0Q62BGwCaAmWM
QPtnrQHixbzh2BlQcO27g0w=
=XEQp
-----END PGP SIGNATURE-----
 
G

George Sakkis

Heiko Wundram said:
Not always. Say for example that you're doing some 2D geometry stuff, and
later you have to extend it to 3D. In this case you may have to deal with
both 2D and 3D objects, and map the former to the latter when necessary.

But this rather sounds like you'd want an adaptor iterator, like the
following:
... def __init__(self,data):
... self.data = data
... def __iter__(self):
... for item in self.data:
... if len(item) == 2:
... yield item+(0,)
... else:
... yield item
...
for x,y,z in AdaptPossible2D([(1,2),(1,2,3),(3,4)]):
... print x,y,z
...
1 2 0
1 2 3
3 4 0

Using the above code makes it absolutely clear what you want, and doesn't need
any new syntax which can be ambiguous like (x=0,y,z=0), etc. The above idiom
also takes only constant extra space, as it doesn't duplicate the list during
iteration.


Once more, the 2D/3D example was just that, an example; my point was not to find a specific solution
to a specific problem. Extending the "for .. in" syntax would be an elegant way to express this idea
in a more succint, familiar and generic way than a customized adaptor. As for the ambiguity, it is
not more ambiguous than function signatures as long as all keyword arguments go after all the
required ones; I'm not suggesting that (x=0,y,z=0) should be valid.

George
 
G

George Sakkis

Heiko Wundram said:
Am Sonntag, 20. März 2005 22:22 schrieb George Sakkis:

And my point being: it's simple enough to give a general recipe (which my
example was) without extending Python's syntax, so why extend the syntax and
not just use a solution derived from that recipe that's working now (and is
backwards compatible at least to 2.3), and which is also clear in itself?

I'm not saying that your syntax looks "strange" or "bad", but there are means
to do what you want to do now, without cumbersome syntax or duplicating code,
and as such I'm -1 on syntactic sugar (TOWTDI and all)...

Don't take this the wrong way, but I think introducing syntax is the wrong
solution to a non-existant problem with the language.

The way I see it, it's closer to applying existing syntax (from function signatures) in a new
context than introducing new syntax, but that's a detail. I guess it's a matter of personal
preference to syntactic sugar then. Still, python is rife with syntactic sugar: iterators, default
function arguments, *varargs, **kwdargs,
  • /(tuple)/{dict} literals, recently @decorators, and
    more. If syntactic sugar didn't matter, we would be happy with scheme's syntax.

    George
 
H

Heiko Wundram

Am Sonntag, 20. März 2005 22:22 schrieb George Sakkis:
Once more, the 2D/3D example was just that, an example; my point was not to
find a specific solution to a specific problem.

And my point being: it's simple enough to give a general recipe (which my
example was) without extending Python's syntax, so why extend the syntax and
not just use a solution derived from that recipe that's working now (and is
backwards compatible at least to 2.3), and which is also clear in itself?

I'm not saying that your syntax looks "strange" or "bad", but there are means
to do what you want to do now, without cumbersome syntax or duplicating code,
and as such I'm -1 on syntactic sugar (TOWTDI and all)...

Don't take this the wrong way, but I think introducing syntax is the wrong
solution to a non-existant problem with the language.

--
--- Heiko.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQBCPfsTf0bpgh6uVAMRAoxEAJ4j6ElTORU6UfghgvugsY7hgZXSgQCfXA6Z
fGuqEyU2FCS+xhJN5i7kiKw=
=DNPb
-----END PGP SIGNATURE-----
 
K

Kay Schluehr

George said:
Looks very appealing, but what to do with

[x*y-z for (x=0,y,z) in (1,2,3), (4,5), (6,7,8)] ?

Should it raise an exception due to a pattern mismatch?

I didn't have in mind to generalize the syntax even more than the respective
for function
signatures, therefore this would be syntax error:
SyntaxError: non-keyword arg after keyword arg

O.K. Allthough it has fallen out of Guidos favor one can use a lambda
to obtain the same solution:

[(lambda x,y,z=0:x*y-z)(*vec) for vec in (1,2,3), (4,5), (6,7,8)]

This inspires to examine Your list comprehension not as plain 'syntax
suggar' but in a clear operational perspective. Since (x,y,z=0) is not
a valid Python tuple we have to replace it by

lambda x,y,z=0:(x,y,z)

This acts on the list elements of the comprehension like the proposed
(x,y,z=0) whereas the valid (x,y,z) acts like

lambda x,y,z:(x,y,z)

So we have generalized tuples to lambdas. If we let lambda
x,y,z=0:(x,y,z) iterate over the list elements, why not the generalized

lambda x,y,z=0:(lambda x,a=0:(x,a),y,z) ?

Returning to Your soluion and translating back the lambda:

[x*y-z for ((x,a=0),y,z=0) in (1,2,3), (4,5), (6,7,8)]

should also be possible from an operational perspective.

Regards Kay
 
R

Ron

I'm sure there must have been a past thread about this topic but I don't know how to find it: How
about extending the "for <X> in" syntax so that X can include default arguments ? This would be very
useful for list/generator comprehensions, for example being able to write something like:

[x*y-z for (x,y,z=0) in (1,2,3), (4,5), (6,7,8)]

instead of the less elegant explicit loop version that has to check for the length of each sequence.
What do you think ?

George

How would this examples work?

for x=5,y,z in (123),(4,5),(6,7,8,9)

Would the x default over ride the first value?
Should, the 4 element in the third tuple be dropped without an error?


A general reusable function might be something like this:

def formatlistofargs(arglist, nargs=1, defvalue=0):
returnvalues = []
for i in arglist:
ii = list(i)
while len(ii)<nargs:
ii.append(defvalue)
ii=ii[:nargs]
returnvalues.append(ii)
return returnvalues

for x,y,z in formatlistofargs(((1,2,3),(3,4),(5,6,7,8)),3):
print x,y,z


Ron
 
G

George Sakkis

Ron said:
How would this examples work?

for x=5,y,z in (123),(4,5),(6,7,8,9)

Would the x default over ride the first value?
Should, the 4 element in the third tuple be dropped without an error?

It has already been clarified twice in the thread that the default values would be allowed *only in
the end*, exactly as default function arguments.
A general reusable function might be something like this:

def formatlistofargs(arglist, nargs=1, defvalue=0):
returnvalues = []
for i in arglist:
ii = list(i)
while len(ii)<nargs:
ii.append(defvalue)
ii=ii[:nargs]
returnvalues.append(ii)
return returnvalues

for x,y,z in formatlistofargs(((1,2,3),(3,4),(5,6,7,8)),3):
print x,y,z

Of course there are ways to have a function fill in the defaults, but syntactically I would find
"for (x,y,z=0) in (1,2,3), (4,5), (6,7,8): print x,y,z" more obvious and concise.

By the way, I don't think it's a good idea in general to drop the extra values implicitly, as you do
in your recipe, for the same reason that calling a function foo(x,y,z) as foo(1,2,3,4) is an error.
A generalization of the 'for .. in' syntax that would handle extra arguments the same way as
functions would be:

for (x,y,z=0,*rest) in (1,2,3), (3,4), (5,6,7,8):
print x, y, z, rest

I'd love to see this in python one day; it is pretty obvious what it would do for anyone familiar
with function argument tuples.

George
 
J

Jeff Shannon

George said:
A generalization of the 'for .. in' syntax that would handle
> extra arguments the same way as functions would be:

for (x,y,z=0,*rest) in (1,2,3), (3,4), (5,6,7,8):
print x, y, z, rest

I'd love to see this in python one day; it is pretty obvious what
> it would do for anyone familiar with function argument tuples.

Let's all keep in mind that for...in... is using standard tuple
unpacking rules (you're getting the next tuple from a list of tuples,
and then unpacking that tuple), so what is really being proposed are
extensions to tuple unpacking. (Making this work in the context of a
for loop but not work in other tuple-unpacking situations would create
inconsistency.)

Function arguments are *not* (in general) a case of tuple unpacking,
on the other hand, so the parallels between function arguments and for
loop control-variable tuples are not so straightforward as is being
claimed.

There may be valid arguments in favor of enhancing tuple unpacking in
this way (indeed, I believe I recall a thread or two on this subject),
but it's important to consider the general consequences, not just the
single aspect of for-loop usage.

Jeff Shannon
 
T

Terry Reedy

George Sakkis said:
A generalization of the 'for .. in' syntax that would handle
extra arguments the same way as functions would be:

for (x,y,z=0,*rest) in (1,2,3), (3,4), (5,6,7,8):
print x, y, z, rest

I'd love to see this in python one day; it is pretty obvious
what it would do for anyone familiar with function argument tuples.

Jeff covered the obvious objection that this is a change from assignment
sematics to function call semantics. Slightly less obvious is that this
will slow down everyone's for loops for the benefit of the very few who
would want to do such a thing. (Is the above based on a real use case?)
Python function calls are 'slow' (relative to assignment, certainly) in
part *because* of the great flexibility in call signatures.

In any case, one can now write (with hardcoded format and types, untested):

def argify(*tups):
for tup in tups:
ltup = len(tup)
if ltup >= 4: yield tup[0:3] + (tup[3:],)
elif ltup == 3: yield tup + ((),)
elif ltup == 2: yield tup + (0, ())
else: raise TypeError("Tuple %s needs at least 2 items"
% (tup,)

for x,y,z,rest in argify(....): print x,y,x,rest

Terry J. Reedy
 
G

Greg Ewing

Jeff said:
Function arguments are *not* (in general) a case of tuple unpacking, on
the other hand, so the parallels between function arguments and for loop
control-variable tuples are not so straightforward as is being claimed.

It seems to me the parallel is close enough that no
confusion would result.

Can you think of any situation in which surprising
behaviour would occur through someone thinking the
parallel was closer than it is?
 
R

Ron

It has already been clarified twice in the thread that the default values would be allowed *only in
the end*, exactly as default function arguments.

Was just asking if there should be other special general cases. What
programmers want usually depend on the problem at hand. imho :)
Of course there are ways to have a function fill in the defaults, but syntactically I would find
"for (x,y,z=0) in (1,2,3), (4,5), (6,7,8): print x,y,z" more obvious and concise.

By the way, I don't think it's a good idea in general to drop the extra values implicitly, as you do
in your recipe, for the same reason that calling a function foo(x,y,z) as foo(1,2,3,4) is an error.
A generalization of the 'for .. in' syntax that would handle extra arguments the same way as
functions would be:

for (x,y,z=0,*rest) in (1,2,3), (3,4), (5,6,7,8):
print x, y, z, rest

I'd love to see this in python one day; it is pretty obvious what it would do for anyone familiar
with function argument tuples.

George

I would probably do it this way myself:

def padlist(alist,length,pad):
alist[length:]=[pad]*(length-len(alist))
return alist

for xyz in [1,2,3],[3,4],[5,6,7]:
x,y,z = padlist(xyz, 3, 0)
print x,y,z

# or this if it's faster:

for x,y,z in [padlist(xyz,3,0) for xyz in [1,2,3],[3,4],[5,6,7]]:
print x,y,z


Which isn't too different from what you are suggesting. I think
someone may have already suggested using list comprehensions.

Ron
 
K

Kay Schluehr

Terry said:
Jeff covered the obvious objection that this is a change from assignment
sematics to function call semantics.
Slightly less obvious is that this
will slow down everyone's for loops for the benefit of the very few who
would want to do such a thing.

If the action of (x,y,z=0) on a tuple is regarded as a function call
why not letting resolve it by the compiler in an appropriate manner?
The tuple assignment is just a special case of this and can be resolved
in a different way. There would be no slowdown at all.

Regards Kay
 

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
474,222
Messages
2,571,142
Members
47,775
Latest member
MadgeMatti

Latest Threads

Top