By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,091 Members | 1,546 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,091 IT Pros & Developers. It's quick & easy.

python3: 'where' keyword

P: n/a
Hi.

It would be great to be able to reverse usage/definition parts in
haskell-way with "where" keyword. Since Python 3 would miss lambda, that
would be extremly useful for creating readable sources.

Usage could be something like:
res = [ f(i) for i in objects ] where:
def f(x):
#do something
or
print words[3], words[5] where:
words = input.split()
- defining variables in "where" block would restrict their visibility to
one expression

- it's more easy to read sources when you know which part you can skip,
compare to
def f(x):
#do something
res = [ f(i) for i in objects ]


in this case you read definition of "f" before you know something about
it usage.
Jul 18 '05 #1
Share this Question
Share on Google+
47 Replies


P: n/a
Andrey Tatarinov wrote:
Hi.

It would be great to be able to reverse usage/definition parts in
haskell-way with "where" keyword. Since Python 3 would miss lambda, that
would be extremly useful for creating readable sources.

Usage could be something like:
>>> res = [ f(i) for i in objects ] where:
>>> def f(x):
>>> #do something
or
>>> print words[3], words[5] where:
>>> words = input.split()
- defining variables in "where" block would restrict their visibility to
one expression
How often is this really necessary? Could you describe some benefits of
this? I think the only time I've ever run into scoping problems is with
lambda, e.g.

[lambda x: f(x) for x, f in lst]

instead of

[lambda x, f=f: for x, f in lst]

Are there other situations where you run into these kinds of problems?
- it's more easy to read sources when you know which part you can skip,
compare to
>>> def f(x):
>>> #do something
>>> res = [ f(i) for i in objects ]


in this case you read definition of "f" before you know something about
it usage.


Hmm... This seems very heavily a matter of personal preference. I find
that your where clause makes me skip the 'res' assignment to read what
the 'res' block contains. I had to read it twice before I actually
looked at the list comprehension. Of course, I'm sure I could be
retrained to read it the right way, but until I see some real benefit
from it, I'd rather not have to.
TOOWTDI-ily-yrs,

Steve
Jul 18 '05 #2

P: n/a
Steven Bethard wrote:
How often is this really necessary? Could you describe some benefits of
this? I think the only time I've ever run into scoping problems is with
lambda, e.g.

[lambda x: f(x) for x, f in lst]

instead of

[lambda x, f=f: for x, f in lst]


Sorry, bad example, this should have looked something more like:

[lambda y: f(x, y) for x, f in lst]

....

[lambda y, x=x, f=f: f(x, y) for x, f in lst]

where you actually need the lambda.

Steve
Jul 18 '05 #3

P: n/a
In article <xd********************@comcast.com>,
Steven Bethard <st************@gmail.com> wrote:
Andrey Tatarinov wrote:

It would be great to be able to reverse usage/definition parts in
haskell-way with "where" keyword. Since Python 3 would miss lambda, that
would be extremly useful for creating readable sources.

Usage could be something like:
>>> res = [ f(i) for i in objects ] where:
>>> def f(x):
>>> #do something


or
>>> print words[3], words[5] where:
>>> words = input.split()


- defining variables in "where" block would restrict their visibility to
one expression


How often is this really necessary? Could you describe some benefits of
this? I think the only time I've ever run into scoping problems is with
lambda, e.g.

[lambda x: f(x) for x, f in lst]

instead of

[lambda x, f=f: for x, f in lst]

Are there other situations where you run into these kinds of problems?


Note that he says "would be extremely useful for creating readable
sources", so the "these kinds of problems" he would have been thinking
of would be where source was not as readable as it could be. You seem
to be concerned about something else.

I don't by any means agree that this notation is worth adopting, and
in general I think this kind of readability issue is more or less a lost
cause for a language with Python's scoping rules, but the motive makes
sense to me. One way to look at it might be, if I observe that "words"
is assigned to in a where clause, then I know it will not be used
elsewhere in the surrounding scope so I can forget about it right away.
If the name does occur elsewhere, it evidently refers to something else.

Donn Cave, do**@u.washington.edu
Jul 18 '05 #4

P: n/a
Andrey Tatarinov wrote:
Hi.

It would be great to be able to reverse usage/definition parts in
haskell-way with "where" keyword. Since Python 3 would miss lambda, that
would be extremly useful for creating readable sources.

Usage could be something like:
>>> res = [ f(i) for i in objects ] where:
>>> def f(x):
>>> #do something
I don't know haskell, but it looks SQL-ish to me (only by loose
association). And it's not that unpythonic - it resembles
res = [x for x in sequence if x.isOk()]
or
>>> print words[3], words[5] where:
>>> words = input.split()

Here's a shorter version:
print input.split()[3:5:2]

(Does it qualify as obfuscated Python code? :) )
- defining variables in "where" block would restrict their visibility to
one expression

- it's more easy to read sources when you know which part you can skip,
Yes, I like the readability of it, too.
compare to
>>> def f(x):
>>> #do something
>>> res = [ f(i) for i in objects ]


in this case you read definition of "f" before you know something about
it usage.


When I first read your post, I thought "Well, just one more of those
Py3k ideas that appear on c.l.py every day." But as I look at the latter
example, I think you have just scratched my itch. The same thing has
bugged me more than once in my code.

I think this idea is of the same kind as the @decorator syntax. Guido
moved an operation to a point in the code where it was more visible. You
moved an operation to a more local context where (pun not intended) it
really belongs.

I'm usually rather conservative about Python syntax (@decorators,
absolute/relative imports, if-else operator), but this one could appear
in Python tomorrow and that would be too far in the future for me ;)

Cheers,

AdSR
Jul 18 '05 #5

P: n/a
Donn Cave <do**@u.washington.edu> writes:
I don't by any means agree that this notation is worth adopting, and
in general I think this kind of readability issue is more or less a lost
cause for a language with Python's scoping rules, but the motive makes
sense to me.


But we're talking about the mythical/hypothetical Python 3, so maybe
there's a chance of fixing the scoping rules, which it seems to me are
currently pretty badly broken.
Jul 18 '05 #6

P: n/a
Andrey Tatarinov wrote:
Hi.

It would be great to be able to reverse usage/definition parts in
haskell-way with "where" keyword. Since Python 3 would miss lambda, that
would be extremly useful for creating readable sources.

Usage could be something like:
>>> res = [ f(i) for i in objects ] where:
>>> def f(x):
>>> #do something


Hmm, this is actually a really interesting idea. Avoiding accidental namespace
conflicts is certainly one of the advantages of using lambdas.

This idea has the virtue of being able to do the same thing, but have full
access to Python's function syntax and assignment statements in the 'expression
local' suite.

In fact, any subexpressions in a complicated expression can be extracted and
named for clarity without fear of screwing up the containing namespace, which
would be an enormous boon for software maintainers.

It also allows the necessary but uninteresting setup for an expression to be
moved "out of the way", bringing the expression that does the real work to
prominence.

From the interpreter's point of view, the meaning would probably be something like:

namespace = locals()
exec where_suite in globals(), namespace
exec statement in globals(), namespace
res = namespace["res"]
del namespace

Making the 'where' clause part of the grammar for the assignment statement
should be enough to make the above example parseable, too.

The clause might actually make sense for all of the simple statement forms in
the grammar which contain an expression:
expression statement
assignment statement
augmented assignment statement
del statement
print statement
return statement
yield statement
raise statement
exec statement

The clause really isn't appropriate for break, continue, import or global
statements, as they don't contain any expressions :)

For compound statements, a where clause probably isn't appropriate, as it would
be rather unclear what the where clause applied to.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #7

P: n/a
Nick Coghlan <nc******@iinet.net.au> writes:
Usage could be something like:
>>> res = [ f(i) for i in objects ] where:
>>> def f(x):
>>> #do something

Hmm, this is actually a really interesting idea. Avoiding accidental
namespace conflicts is certainly one of the advantages of using lambdas.


I like it too. Seems a little perl-ish, but what the hey.
In fact, any subexpressions in a complicated expression can be
extracted and named for clarity without fear of screwing up the
containing namespace, which would be an enormous boon for software
maintainers.


Sure, why not:

x = (-b + sqrt(discriminant))/(2*a) where:
discriminant = b*b - 4*a*c

Maybe you could just have a where: suite that binds variables
within the suite:

where:
def f(x):
#do something
res = [ f(i) for i in objects ]

where:
discriminant = b*b - 4*a*c
x = (-b + sqrt(discriminant))/(2*a)

Syntax is
where:
suite
statement

the suite has its own scope so any variable created there is local to
the suite plus the following statement. The scope vanishes after the
statement.
Jul 18 '05 #8

P: n/a
Nick Coghlan wrote:
It also allows the necessary but uninteresting setup for an expression
to be moved "out of the way", bringing the expression that does the real
work to prominence.


Killer app for this keyword:

class C(object):

x = property(get, set) where:
def get(self):
return "Silly property"
def set(self, val):
self.x = "Told you it was silly"

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #9

P: n/a
Paul Rubin wrote:
the suite has its own scope so any variable created there is local to
the suite plus the following statement. The scope vanishes after the
statement.


The second part of the idea is to give the statement greater prominence and
'hide' the uninteresting setup (the contents of the where clause).

Putting the statement of interest after the where suite still gives the benefits
of avoiding namespace clutter, but doesn't really help readability (it makes it
worse, if you ask me).

Particularly, what if the next statement is a compound statement?

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #10

P: n/a
But we're talking about the mythical/hypothetical Python 3, so maybe
there's a chance of fixing the scoping rules, which it seems to me are currently pretty badly broken.


I don't think the current scoping rules will be changed in Python 3.0.
I can't give you the link right now, but there are threads about the
scope rules in
python-dev, with various people protesting and Guido saying that he
wants to
keep them as they are.

Michele Simionato

Jul 18 '05 #11

P: n/a
Nick Coghlan wrote:
Andrey Tatarinov wrote:
Hi.

It would be great to be able to reverse usage/definition parts in
haskell-way with "where" keyword. Since Python 3 would miss lambda, that would be extremly useful for creating readable sources.

Usage could be something like:
>>> res = [ f(i) for i in objects ] where:
>>> def f(x):
>>> #do something

[snip] For compound statements, a where clause probably isn't appropriate, as it would be rather unclear what the where clause applied to.


Right. But you know that as soon as you add this to simple
expressions, a bunch of people are going to come here whining about how
they don't get to use where with if-expressions.

Frankly, they might have a point here. Although we have replacing
lambda expressions on our minds, I have in mind a different problem
that a where-statement would solve perfectly. But it would have to be
used with an if-expression.

However, I think it might not be so hard. Let's take Paul Rubin's
advice and precede the if statement with where. Let's also allow
"elif" clauses to be replaced with "else where ... if" clauses. That
which is bound in the while-block would be visible in both the
if-expression and if-block.

Then we could do this:

.. where:
.. m = someregexp.match(somestring)
.. if m:
.. blah blah blah
.. else where:
.. m = someotherregexp.match(somestring)
.. if m:
.. blah blah blah

We might want to spell "else where" instead as "elwhere", to match
"elif", but that's not important now. This would take away one of the
major minor annoyances of Python. (In fact, I've suggested something
like this as a solution to the set-and-test idiom, which Python makes
difficult, only I used the keyword "suppose" instead of "where".)

Ok, but if you do that, now you have people whining that "where" comes
after some expressions, and before others. (This would not bother me
one bit, BTW, but I'm pretty sure I'd lose the popular vote on this
one.)

So, let's go all out and say that while could precede any statement.
We now have consistency. Well, that really wouldn't work for the
if-statement, though, because then how could we apply a different
while-block to an else clause? We'd have to treat if-statements
specially anyways. So we don't have consistency.

My solution would be to propose two different where statements: a
where...do statement, and a separate where...if statement. The
where...do statement would look like this:

.. where:
.. def whatever(): pass
.. do:
.. blah blah use whatever blah

It has the advantage of being able to apply the where bindings to
several statements, and is, IMO, much cleaner looking than simply
applying where's bindings to the single following unindented statement.

I would recommend against where...while and where...for statements.
They can't accomplish anything you couldn't do with a break statement
inside the block, and it's not obvious whether the where clause gets
executed once or for each loop (since it's physically outside the loop
part).

One question: what do you do with a variable bound inside a while-block
that has the same name as a local variable? (Or, horrors, a
surrounding while-block?) I'm inclined to think it should be illegal,
but maybe it would be too restrictive.
Anyways, I like this idea a lot.

+1
--
CARL BANKS

Jul 18 '05 #12

P: n/a
Carl Banks wrote:
Right. But you know that as soon as you add this to simple
expressions, a bunch of people are going to come here whining about how
they don't get to use where with if-expressions.

Frankly, they might have a point here. Although we have replacing
lambda expressions on our minds, I have in mind a different problem
that a where-statement would solve perfectly. But it would have to be
used with an if-expression.


I have a different suggestion for this.

'as' is used for renaming in import statements. 'as' will be used for exception
naming in Python 3k.

So let's use it for expression naming in 'if' statements, too.

if someregexp.match(s) as m:
# blah using m
elif someotherregexp.match(s) as m:
# blah using m

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #13

P: n/a
Nick Coghlan <nc******@iinet.net.au> writes:
So let's use it for expression naming in 'if' statements, too.

if someregexp.match(s) as m:
# blah using m
elif someotherregexp.match(s) as m:
# blah using m


Certainly an improvement over what we have now.
Jul 18 '05 #14

P: n/a
Nick Coghlan wrote:

Killer app for this keyword:

class C(object):

x = property(get, set) where:
def get(self):
return "Silly property"
def set(self, val):
self.x = "Told you it was silly"


Hey, this is super-elegant!

AdSR
Jul 18 '05 #15

P: n/a
AdSR <ad**@poczta.onet.pl> writes:
Killer app for this keyword:
class C(object):
x = property(get, set) where:
def get(self):
return "Silly property"
def set(self, val):
self.x = "Told you it was silly"


Hey, this is super-elegant!


Heh, even further:

z = C() where:
class C(object):
...

Lets you make anonymous classes and singleton objects.
Jul 18 '05 #16

P: n/a
On Sat, 08 Jan 2005 16:42:16 +1000, Nick Coghlan <nc******@iinet.net.au> wrote:
Nick Coghlan wrote:
It also allows the necessary but uninteresting setup for an expression
to be moved "out of the way", bringing the expression that does the real
work to prominence.


Killer app for this keyword:

class C(object):

x = property(get, set) where:
def get(self):
return "Silly property"
def set(self, val):
self.x = "Told you it was silly"


Yes, that is cool and it _is_ an interesting idea. Are suites nestable? E.g., is this legal?

x = term1 + term2 where:
term1 = a*b where:
a = 123
b = 456
term2 = math.pi

Reminds me of some kind of weird let ;-)

And, is the whole thing after the '=' an expression? E.g.,

x = ( foo(x) where:
x = math.pi/4.0
) where:
def foo(x): print 'just for illustration', x

or is this legal?

for y in ([foo(x) for x in bar] where:
bar = xrange(5)
): baz(y) where:
def baz(arg): return arg*2

Not trying to sabotage the idea, really, just looking for clarification ;-)

Regards,
Bengt Richter
Jul 18 '05 #17

P: n/a
Bengt Richter wrote:
It also allows the necessary but uninteresting setup for an expression
to be moved "out of the way", bringing the expression that does the real
work to prominence.Killer app for this keyword:

class C(object):

x = property(get, set) where:
def get(self):
return "Silly property"
def set(self, val):
self.x = "Told you it was silly"

Yes, that is cool and it _is_ an interesting idea. Are suites nestable? E.g., is this legal?

.... And, is the whole thing after the '=' an expression? E.g.,

x = ( foo(x) where:
x = math.pi/4.0
) where:
def foo(x): print 'just for illustration', x

or is this legal?

for y in ([foo(x) for x in bar] where:
bar = xrange(5)
): baz(y) where:
def baz(arg): return arg*2

Not trying to sabotage the idea, really, just looking for clarification ;-)


yes, all your examples are correct. And that's the way I'd like to use
this feature.
Jul 18 '05 #18

P: n/a
Nick Coghlan wrote:
It also allows the necessary but uninteresting setup for an expression
to be moved "out of the way", bringing the expression that does the
real work to prominence.

Killer app for this keyword:

class C(object):

x = property(get, set) where:
def get(self):
return "Silly property"
def set(self, val):
self.x = "Told you it was silly"


oh, that's great! I can't imagine prettier example
Jul 18 '05 #19

P: n/a
At the risk of generating controversy, here's another type of example:

def gcd(a, b):
where:
a: int, b: int
return c where:
c: int
while a:
a, b = b%a, a
return b

More can be found at http://aroberge.blogspot.com

Andre

Jul 18 '05 #20

P: n/a
Darn space-eater google groups :-( Here is it again, at teh risk of
generating controversy

..def gcd(a, b):
.. where:
.. a: int, b: int
.. return c where:
.. c: int
.. while a:
.. a, b = b%a, a
.. return b
more examples can be found at aroberge.blogspot.com

André

Jul 18 '05 #21

P: n/a
When I first saw this I thought: "hmmm... this seems as redundant as
adding a repeat/until loop to Python; there's no chance in hell it will
ever be accepted by the community or Guido, but I actually kinda like
it". It's nice to see mostly positive reactions to this idea so far.

I think it's a really ingenious solution to the the anonymous function
problem - don't make it anonymous! A short, throwaway name with a very
localized scope is as good as a truly anonymous function and feels more
Pythonic to me. We thought we wanted a better syntax than lambda for
anonymous functions but Andrey shows that perhaps it wasn't what we
really need. What we need is a solution to quickly and cleanly generate
bits of callable code without polluting the containing namespace,
without having to think too hard about unique names and while making
their temporary and local nature clear from the context. Anonymity
isn't one of the requirements.

I really liked Nick Coghlan's property example. The names 'get' and
'set' are too short and generic to be used without a proper scope but
with this syntax they are just perfect.

Here's another example:

w = Widget(color=Red, onClick=onClick, onMouseOver=onMouseOver) where:
.. def onClick(event): do_this(event.x, event.y, foo)
.. def onMouseOver(event): someotherwidget.do_that()

The "onClick=onClick" part seems a bit redundant, right? So how about
this:

w = Widget(**kw) where:
.. color = Red
.. def onClick(event): do_this(event.x, event.y, blabla)
.. def onMouseOver(event): someotherwidget.do_that()
.. x, y = 100, 200
.. kw = locals()

I'm not really sure myself how much I like this. It has a certain charm
but also feels like abuse of the feature. Note that "w =
Widget(**locals()) where:" would produce the wrong result as it will
include all the values in the containing scope, not just those defined
in the where block.

Oren

Jul 18 '05 #22

P: n/a
Andrey Tatarinov wrote:
>>> print words[3], words[5] where:
>>> words = input.split()


- defining variables in "where" block would restrict their visibility to
one expression


Then your example above doesn't work... print takes a
sequence of expressions, not a tuple as you seem to think.

-Peter
Jul 18 '05 #23

P: n/a
On Sat, 08 Jan 2005 12:53:05 -0500, Peter Hansen <pe***@engcorp.com> wrote:
Andrey Tatarinov wrote:
>>> print words[3], words[5] where:
>>> words = input.split()


- defining variables in "where" block would restrict their visibility to
one expression


Then your example above doesn't work... print takes a
sequence of expressions, not a tuple as you seem to think.


I found it strange that he had chosen to make the example with
"print", that is a statement. I'm not sure how could it be made to
work with both expressions and statements, it just seems strange...

Overall, I found the idea interesting. It seems like a obvious
counterpart to "with", in the sense that both act as modifiers to the
scoping rules. I think it can be made to work, and that it would lead
to elegant & readable code, but there are still lots of things to
consider: exception handling, fast name lookup in the "where" block,
access to symbols outside the "where" block, just to name a few.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #24

P: n/a
Peter Hansen wrote:
Andrey Tatarinov wrote:
>>> print words[3], words[5] where:
>>> words = input.split()


- defining variables in "where" block would restrict their visibility to one expression


Then your example above doesn't work... print takes a
sequence of expressions, not a tuple as you seem to think.


You misunderstand. There "where" is not part of the expression but the
statement. The above example would be a modified print statement, a
print...where statement, if you will. Under this suggestion, there
would be modified versions of various simple statements.

This wouldn't be a problem parsing, of course, because "where" would be
a keyword.
--
CARL BANKS

Jul 18 '05 #25

P: n/a
"Carl Banks" <in**********@aerojockey.com> writes:
You misunderstand. There "where" is not part of the expression but the
statement. The above example would be a modified print statement, a
print...where statement, if you will. Under this suggestion, there
would be modified versions of various simple statements.


You mean I can't say

# compute sqrt(2) + sqrt(3)
x = (sqrt(a) where:
a = 2.) \
+ sqrt (a) where:
a = 3.

Hmmm.
Jul 18 '05 #26

P: n/a

Bengt Richter wrote:
And, is the whole thing after the '=' an expression? E.g.,

x = ( foo(x) where:
x = math.pi/4.0
) where:
def foo(x): print 'just for illustration', x
How would that be any improvement over this?

.. x = foo(x) where:
.. x = math.pi/4.0
.. def foo(x): print 'just for illustration', x

Can anyone think of a use case for embedding "where" inside an
expression as opposed to making it part of a simple statement? And, if
so, is the benefit of it worth the massive hit in readability.

or is this legal?

for y in ([foo(x) for x in bar] where:
bar = xrange(5)
): baz(y) where:
def baz(arg): return arg*2
Here, I can only hope not. One reason I proposed a where...do syntax
is so that, if you wanted to localize a variable to a for loop or some
other compound statement, you could do it with a minimum of fuss.

.. where:
.. bar = xrange(5)
.. def baz(arg): return arg*2
.. do:
.. for y in [foo(x) for x in bar]:
.. baz(y)

Not trying to sabotage the idea, really, just looking for

clarification ;-)

That's ok. For it fly, it's got to be able to withstand the flak.
--
CARL BANKS

Jul 18 '05 #27

P: n/a

Paul Rubin wrote:
"Carl Banks" <in**********@aerojockey.com> writes:
You misunderstand.
BTW, Peter, I guess I should have said "I misunderstand, but it can be
legal if you consider it part of the statements", since it appears the
author did intend it to be part of an expression.

There "where" is not part of the expression but the
statement. The above example would be a modified print statement, a print...where statement, if you will. Under this suggestion, there
would be modified versions of various simple statements.


You mean I can't say

# compute sqrt(2) + sqrt(3)
x = (sqrt(a) where:
a = 2.) \
+ sqrt (a) where:
a = 3.

Hmmm.


What would be the advantage of that over this?

.. x = sqrt(a) + sqrt(b) where:
.. a = 2.0
.. b = 3.0

Where would making "where" part of an expression rather than part of
the statement help? Can you think of a place? ("That it makes Python
more like LISP" is not a good enough answer for me, BTW. But feel free
to try. :)
--
CARL BANKS

Jul 18 '05 #28

P: n/a
"Carl Banks" <in**********@aerojockey.com> writes:
# compute sqrt(2) + sqrt(3)
x = (sqrt(a) where:
a = 2.) \
+ sqrt (a) where:
a = 3.

Hmmm.


What would be the advantage of that over this?

. x = sqrt(a) + sqrt(b) where:
. a = 2.0
. b = 3.0


The idea of "where" is to allow re-using variable names instead of
having to keep track of which ones are in use. I just tried to give a
very simple example of how you might do that more than once in a
statement.
Jul 18 '05 #29

P: n/a
Nick Coghlan wrote:
I have a different suggestion for this.

'as' is used for renaming in import statements. 'as' will be used for exception naming in Python 3k.

So let's use it for expression naming in 'if' statements, too.

if someregexp.match(s) as m:
# blah using m
elif someotherregexp.match(s) as m:
# blah using m

What if the condition you wanted to test wasn't the same as the thing
you want to save? In other words, how would you convert this?

.. where:
.. m = something()
.. if m > 20:
.. do_something_with(m)

What you propose works for typical regexps idiom but not for the
slightly more general case. However, I could see why some people might
not like the where...if syntax I proposed; it's kind of choppy and not
exactly easy to follow at a first glance.

As a compromise, howabout:

.. if m > 20 where m=something():
.. do_something_with(m)

In this case, the m=something() is NOT an assignment statement, but
merely a syntax resembling it. The "where m=something()" is part of
the if-statement, not the if-expression. It causes m to be visisble in
the if-expression and the if-block.

It (or your suggestion) could work with a while-loop too.

.. while line where line=f.readline():
.. do_something_with(line)
The main problem here (as some would see it) is that you can't do
something this:

.. if m > 20 where (def m(): a(); b()):
--
CARL BANKS

Jul 18 '05 #30

P: n/a
Paul Rubin wrote:
"Carl Banks" <in**********@aerojockey.com> writes:
When I asked you to do this, it was just a rhetorical way to tell you
that I didn't intend to play this game. It's plain as day you're
trying to get me to admit something. I'm not falling for it.

If you have a point to make, why don't you just make it?

You asked me to compare the notion of macros with the Zen list. I did
so. I didn't see any serious conflict, and reported that finding.
Now you've changed your mind and you say you didn't really want me to
make that comparison after all.

Well I for one disagreed with many of your estimates of the zen's
applicability to macros, but I just couldn't be arsed saying so.
An amazing amount of the headaches that both newbies and experienced
users have with Python, could be solved by macros. That's why there's
been an active interest in macros for quite a while. It's not clear
what the best way to do design them is, but their existence can have a
profound effect on how best to do these ad-hoc syntax extensions like
"where". Arbitrary limitations that are fairly harmless without
macros become a more serious pain in the neck if we have macros.
This is not a justifiable assertion, IMHO, and if you think that newbies
will have their lives made easier by the addition of ad hoc syntax
extensions then you and I come from a different world (and I suspect the
walls might be considerably harder in mine than in yours).
So, we shouldn't consider these topics separately from each other.
They are likely to end up being deeply related.


I don't really understand why, if macros are so great (and you are
reading the words of one who was using macros back in the days of
Strachey's GPM) why somebody doesn't produce a really useful set of
(say) M4 macros to prove how much they'd improve Python.

Now that's something that would be a bit less ignorable than this
apparently interminable thread.

regards
Steve

PS: Your continued use of the NOSPAM.invalid domain is becoming much
more irritating than your opinions on macros in Python. Using a bogus
URL is piling crap on top of more crap.
--
Steve Holden http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/
Holden Web LLC +1 703 861 4237 +1 800 494 3119
Jul 18 '05 #31

P: n/a
Steve Holden <st***@holdenweb.com> writes:
Well I for one disagreed with many of your estimates of the zen's
applicability to macros, but I just couldn't be arsed saying so.
Well, I was being somewhat flip with them, as I felt Carl was being
snotty in referring me to the Zen list. The point there is that one
can interpret each of the Zen points in many ways regarding macros. I
don't feel there's a conflict between macros and the Zen list. Macros
in Python are a deep subject and gurus have been discussing them for a
long time. I think that with PyPy it will become easier to experiment
with possible approaches. In other posts I've suggested a moratorium
on new Python syntax until after PyPy is deployed.
An amazing amount of the headaches that both newbies and experienced
users have with Python, could be solved by macros.... It's not clear
what the best way to do design them is, but their existence can have a
profound effect on how best to do these ad-hoc syntax extensions like
"where".

This is not a justifiable assertion, IMHO, and if you think that
newbies will have their lives made easier by the addition of ad hoc
syntax extensions then you and I come from a different world (and I
suspect the walls might be considerably harder in mine than in yours).


I'm saying that many proposals for ad hoc extensions could instead be
taken care of with macros. Newbies come to clpy all the time asking
how to do assignment expressions, or conditional expressions, or
call-by-reference. Sometimes new syntax results. Lots of times,
macros could take care of it.
I don't really understand why, if macros are so great (and you are
reading the words of one who was using macros back in the days of
Strachey's GPM) why somebody doesn't produce a really useful set of
(say) M4 macros to prove how much they'd improve Python.


You can't really do Python macros with something like M4. How would
M4 even generate multi-line output that's indented to the right depth
for the place where the macro was called? How would you write an
m4 macro like cond(x,y,z) that does the equivalent of (x ? y : z)?
Even if you could, it doesn't begin to address the hassle of running
Python scripts through m4 before you can execute the scripts, especially
in an interactive environment.
Jul 18 '05 #32

P: n/a
Nick Coghlan wrote:
Semantics
---------
The code::

<statement> with:
<suite>

translates to::

def unique_name():
<suite>
<statement>
unique_name()


Bleh. Not only was my proposed grammar change wrong, my suggested semantics are
wrong, too.

Raise your hand if you can see the problem with applying the above semantics to
the property descriptor example.

So I think the semantics will need to be more along the lines of "pollute the
namespace but mangle the names so they're unique, and the programmer can *act*
like the names are statement local".

This will be much nicer in terms of run-time performance, but getting the
locals() builtin to behave sensibly may be a challenge.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #33

P: n/a
Nick Coghlan wrote:
Semantics
---------
The code::

<statement> with:
<suite>

translates to::

def unique_name():
<suite>
<statement>
unique_name()


Bleh. Not only was my proposed grammar change wrong, my suggested
semantics are wrong, too.

Raise your hand if you can see the problem with applying the above
semantics to the property descriptor example.

So I think the semantics will need to be more along the lines of
"pollute the namespace but mangle the names so they're unique, and the
programmer can *act* like the names are statement local".

This will be much nicer in terms of run-time performance, but getting
the locals() builtin to behave sensibly may be a challenge.


afair you told yourself that

var = <statement> where:
<suite>

translates to:

def unique_name():
<suite>
return <statement>
var = unique_name()

in this case class gets unique_name() function? is it that bad?

anyway I'd prefer to change semantics deeper. adding new statement-only
scope and adding our suite-definitions there.
Jul 18 '05 #34

P: n/a
Nick Coghlan wrote:
Nick Coghlan wrote:
Semantics
---------
The code::

<statement> with:
<suite>

translates to::

def unique_name():
<suite>
<statement>
unique_name()


Bleh. Not only was my proposed grammar change wrong, my suggested
semantics are wrong, too.

Raise your hand if you can see the problem with applying the above
semantics to the property descriptor example.


Eh, never mind. The following works today, so the semantics I proposed are
actually fine. (This is exactly the semantics proposed for the property example)

Py> class C(object):
.... def _x():
.... def get(self):
.... print "Hi!"
.... def set(self, value):
.... print "Hi again!"
.... def delete(self):
.... print "Bye"
.... return property(get, set, delete)
.... x = _x()
....
Py> C.x
<property object at 0x009E6738>
Py> C().x
Hi!
Py> C().x = 1
Hi again!
Py> del C().x
Bye

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #35

P: n/a
Andrey Tatarinov wrote:
afair you told yourself that

var = <statement> where:
<suite>

translates to:

def unique_name():
<suite>
return <statement>
var = unique_name()

in this case class gets unique_name() function? is it that bad?
No, I wasn't thinking clearly and saw problems that weren't there.

However, you're right that the semantic definition should include unbinding the
unique name after the statement finishes. E.g. for assignments:

def unique_name():
<suite>
return <expr>
<target> = unique_name()
del unique_name
anyway I'd prefer to change semantics deeper. adding new statement-only
scope and adding our suite-definitions there.


A new scope essentially *is* a nested function :)

My main purpose with the nested function equivalent is just to make the intended
semantics clear - whether an implementation actually _does_ things that way is
immaterial.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #36

P: n/a
Andrey Tatarinov wrote:
I think using 'with' keyword can cause some ambiguity. for example I
would surely try to write
>>> x = a+b with self:
>>> b = member
and using with at the end of block brings more ambiguity:
>>> stmt1()
>>> stmt2()
>>> with self:
>>> member = stmt3()
compare to:
>>> stmt1()
>>> stmt2()
>>> with:
>>> variable = stmt3()


a way different semantics with just one word added/deleted.


Except that for a "with <expr>:" block, attributes of the expression must be
preceded by a dot:

Py> stmt1()
Py> stmt2()
Py> with self:
.... .member = stmt3()

The advantages of the 'with' block are that 'self' is only looked up once, and
you only need to type it once. The leading dot is still required to disambiguate
attribute references from standard name references.

Despite that, I think you are right that the ambiguity is greater than I first
thought. Correct code is reasonably easy to distinguish, but in the presence of
errors it is likely to be unclear what was intended, which would make life more
difficult than it needs to be.

However, I still agree with Alex that the dual life of "where" outside of Python
(as an 'additional definitions' clause, as in mathematics, and as a
'conditional' clause, as in SQL), and the varied background of budding
Pythoneers is a cause for concern.

'in' is worth considering, as it is already used by Python at least once for
declaring use of a namespace (in the 'exec' statement). However, I suspect it
would suffer from ambiguity problems similar to those of 'with' (consider
"<expr> in <expr>" and "<expr> in: <expr>"). There's also the fact that the
statement isn't *really* executed in the inner namespace - any name binding
effects are seen in the outer scope, whereas 'exec x in dict' explicitly
protects the containing namespace from alteration.

So of the four keywords suggested so far ('where', 'with', 'in', 'using'), I'd
currently vote for 'using' with 'where' a fairly close second. My vote goes to
'using' because it has a fairly clear meaning ('execute the statement using this
extra information'), and doesn't have the conflicting external baggage that
'where' does.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #37

P: n/a
> So of the four keywords suggested so far ('where', 'with', 'in',
'using'), I'd currently vote for 'using' with 'where' a fairly close
second. My vote goes to 'using' because it has a fairly clear meaning
('execute the statement using this extra information'), and doesn't have
the conflicting external baggage that 'where' does.


I should agree with you =)

Though I love "with" for historical reasons and addiction to functional
languages "using" is not that bad and I do not mind using it. =)
Jul 18 '05 #38

P: n/a
Paul Rubin wrote:
Steve Holden <st***@holdenweb.com> writes:
[...] and if you think that
newbies will have their lives made easier by the addition of ad hoc
syntax extensions then you and I come from a different world (and I
suspect the walls might be considerably harder in mine than in yours).


I'm saying that many proposals for ad hoc extensions could instead be
taken care of with macros. Newbies come to clpy all the time asking
how to do assignment expressions, or conditional expressions, or
call-by-reference. Sometimes new syntax results. Lots of times,
macros could take care of it.


Personally, given the requests in question, I'm extremely thankful
that I don't have to worry about reading Python code that uses them.
I don't *want* people to be able to make up their own
control-structure syntax, because that means I need to be able to
decipher the code of someone who wants to write Visual Basic as
filtered through Java and Perl... If I want mental gymnastics when
reading code, I'd use Lisp (or Forth). (These are both great
languages, and mental gymnastics would probably do me good, but I
wouldn't want it as part of my day-to-day requirements...)

Jeff Shannon
Technician/Programmer
Credit International

Jul 18 '05 #39

P: n/a
Op 2005-01-11, Jeff Shannon schreef <je**@ccvcorp.com>:
Paul Rubin wrote:
Steve Holden <st***@holdenweb.com> writes:
[...] and if you think that
newbies will have their lives made easier by the addition of ad hoc
syntax extensions then you and I come from a different world (and I
suspect the walls might be considerably harder in mine than in yours).
I'm saying that many proposals for ad hoc extensions could instead be
taken care of with macros. Newbies come to clpy all the time asking
how to do assignment expressions, or conditional expressions, or
call-by-reference. Sometimes new syntax results. Lots of times,
macros could take care of it.


Personally, given the requests in question, I'm extremely thankful
that I don't have to worry about reading Python code that uses them.
I don't *want* people to be able to make up their own
control-structure syntax, because that means I need to be able to
decipher the code of someone who wants to write Visual Basic as
filtered through Java and Perl...


No you don't.

You could just as well claim that you don't want people to write
code in other languages because you then would need to be able
to decipher code written in that language.
If I want mental gymnastics when
reading code, I'd use Lisp (or Forth). (These are both great
languages, and mental gymnastics would probably do me good, but I
wouldn't want it as part of my day-to-day requirements...)


Your day-to-day requirements are a contract between you and your
employer or between you and your clients. That you don't want
mental gymnastics as part of that, shouldn't be a concern for
how the language develops.

--
Antoon Pardon
Jul 18 '05 #40

P: n/a
Nick Coghlan wrote:
Semantics
---------
The code::

<statement> with:
<suite>

translates to::

def unique_name():
<suite>
<statement>
unique_name()


I've come to the conclusion that these semantics aren't what I would expect from
the construct. Exactly what I would expect can't really be expressed in current
Python due to the way local name bindings work. The main thing to consider is
what one would expect the following to print:

def f():
a = 1
b = 2
print 1, locals()
print 3, locals() using:
a = 2
c = 3
print 2, locals()
print 4, locals()

I think the least suprising result would be:

1 {'a': 1, 'b': 2} # Outer scope
2 {'a': 2, 'c': 3} # Inner scope
3 {'a': 2, 'b': 2, 'c': 3} # Bridging scope
4 {'a': 1, 'b': 2} # Outer scope

In that arrangement, the statement with a using clause is executed normally in
the outer scope, but with the ability to see additional names in its local
namespace. If this can be arranged, then name binding in the statement with the
using clause will work as we want it to.

Anyway, I think further investigation of the idea is dependent on a closer look
at the feasibility of actually implementing it. Given that it isn't as
compatible with the existing nested scope structure as I first thought, I
suspect it will be both tricky to implement, and hard to sell to the BDFL
afterwards :(

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #41

P: n/a
Nick Coghlan wrote:
def f():
a = 1
b = 2
print 1, locals()
print 3, locals() using:
a = 2
c = 3
print 2, locals()
print 4, locals()

I think the least suprising result would be:

1 {'a': 1, 'b': 2} # Outer scope
2 {'a': 2, 'c': 3} # Inner scope
3 {'a': 2, 'b': 2, 'c': 3} # Bridging scope
4 {'a': 1, 'b': 2} # Outer scope
Personally, I think that the fact that the bridging statement is
executed *after* the inner code block guarantees that results will be
surprising. The fact that it effectively introduces *two* new scopes
just makes matters worse.

It also seems to me that one could do this using a nested function def
with about the same results. You wouldn't have a bridging scope with
both sets of names as locals, but your nested function would have
access to the outer namespace via normal nested scopes, so I'm really
not seeing what the gain is...

(Then again, I haven't been following the whole using/where thread,
because I don't have that much free time and the initial postings
failed to convince me that there was any real point...)

Jeff Shannon
Technician/Programmer
Credit International

In that arrangement, the statement with a using clause is executed
normally in the outer scope, but with the ability to see additional
names in its local namespace. If this can be arranged, then name binding
in the statement with the using clause will work as we want it to.

Anyway, I think further investigation of the idea is dependent on a
closer look at the feasibility of actually implementing it. Given that
it isn't as compatible with the existing nested scope structure as I
first thought, I suspect it will be both tricky to implement, and hard
to sell to the BDFL afterwards :(

Cheers,
Nick.


Jul 18 '05 #42

P: n/a
Nick Coghlan wrote:
Nick Coghlan wrote:
Semantics
---------
The code::

<statement> with:
<suite>

translates to::

def unique_name():
<suite>
<statement>
unique_name()

I've come to the conclusion that these semantics aren't what I would
expect from the construct. Exactly what I would expect can't really be
expressed in current Python due to the way local name bindings work. The
main thing to consider is what one would expect the following to print:

def f():
a = 1
b = 2
print 1, locals()
print 3, locals() using:
a = 2
c = 3
print 2, locals()
print 4, locals()

I think the least suprising result would be:

1 {'a': 1, 'b': 2} # Outer scope
2 {'a': 2, 'c': 3} # Inner scope
3 {'a': 2, 'b': 2, 'c': 3} # Bridging scope
4 {'a': 1, 'b': 2} # Outer scope


as for me, I would expect following:

1 {'a': 1, 'b': 2}
2 {'a': 2, 'b': 2, 'c': 3'}
3 {'a': 2, 'b': 2, 'c': 3'}
4 {'a': 1, 'b': 2}

otherwise that would be impossible to do calculations based on scope
variables and "using:" would be useless =), consider example of usage:

current_position = 1
current_environment # = ...
current_a_lot_of_other_parameters # = ...
scores = [count_score(move) for move in aviable_moves] using:
def count_score(move):
#walking through current_environment
return score
Jul 18 '05 #43

P: n/a
On Thu, 13 Jan 2005 22:41:54 +0300, Andrey Tatarinov <el********@dezcom.mephi.ru> wrote:
Nick Coghlan wrote:
Nick Coghlan wrote:
Semantics
---------
The code::

<statement> with:
<suite>

translates to::

def unique_name():
<suite>
<statement>
unique_name() I've come to the conclusion that these semantics aren't what I would
expect from the construct. Exactly what I would expect can't really be
expressed in current Python due to the way local name bindings work. The
main thing to consider is what one would expect the following to print:

def f():
a = 1
b = 2
print 1, locals()
print 3, locals() using:
a = 2
c = 3
print 2, locals()
print 4, locals()

I think the least suprising result would be:

1 {'a': 1, 'b': 2} # Outer scope
2 {'a': 2, 'c': 3} # Inner scope
3 {'a': 2, 'b': 2, 'c': 3} # Bridging scope
4 {'a': 1, 'b': 2} # Outer scope


as for me, I would expect following:

1 {'a': 1, 'b': 2}
2 {'a': 2, 'b': 2, 'c': 3'}
3 {'a': 2, 'b': 2, 'c': 3'}
4 {'a': 1, 'b': 2}


locals() doesn't automatically show everything that is visible from its local scope:
def foo(): ... a = 1
... b = 2
... print 1, locals()
... def inner():
... a = 2
... c = 3
... print 2, locals()
... inner()
... print 4, locals()
... foo() 1 {'a': 1, 'b': 2}
2 {'a': 2, 'c': 3}
4 {'a': 1, 'b': 2, 'inner': <function inner at 0x02EE8BFC>}

-- unless you actually use it (this is a bit weird maybe?):
def foo(): ... a = 1
... b = 2
... print 1, locals()
... def inner():
... a = 2
... c = 3
... print 2, locals(), 'and b:', b
... inner()
... print 4, locals()
... foo()

1 {'a': 1, 'b': 2}
2 {'a': 2, 'c': 3, 'b': 2} and b: 2
4 {'a': 1, 'b': 2, 'inner': <function inner at 0x02EE8D4C>}

of course a difference using the new syntax is that 'inner' is not bound to a persistent name.

otherwise that would be impossible to do calculations based on scope
variables and "using:" would be useless =), consider example of usage:

current_position = 1
current_environment # = ...
current_a_lot_of_other_parameters # = ...
scores = [count_score(move) for move in aviable_moves] using:
def count_score(move):
#walking through current_environment
return score

No worry, UIAM.

Regards,
Bengt Richter
Jul 18 '05 #44

P: n/a
On Fri, 14 Jan 2005 01:48:48 +1000, Nick Coghlan <nc******@iinet.net.au> wrote:
Nick Coghlan wrote:
Semantics
---------
The code::

<statement> with:
<suite>

translates to::

def unique_name():
<suite>
<statement>
unique_name()


I've come to the conclusion that these semantics aren't what I would expect from
the construct. Exactly what I would expect can't really be expressed in current
Python due to the way local name bindings work. The main thing to consider is
what one would expect the following to print:

def f():
a = 1
b = 2
print 1, locals()
print 3, locals() using:
a = 2
c = 3
print 2, locals()
print 4, locals()

I think the least suprising result would be:

1 {'a': 1, 'b': 2} # Outer scope
2 {'a': 2, 'c': 3} # Inner scope
3 {'a': 2, 'b': 2, 'c': 3} # Bridging scope
4 {'a': 1, 'b': 2} # Outer scope

In that arrangement, the statement with a using clause is executed normally in
the outer scope, but with the ability to see additional names in its local
namespace. If this can be arranged, then name binding in the statement with the
using clause will work as we want it to.

Anyway, I think further investigation of the idea is dependent on a closer look
at the feasibility of actually implementing it. Given that it isn't as
compatible with the existing nested scope structure as I first thought, I
suspect it will be both tricky to implement, and hard to sell to the BDFL
afterwards :(

In the timbot's let/in format:

def f():
a = 1
b = 2
print 1, locals()
let:
a = 2
c = 3
print 2, locals()
in:
print 3, locals()
print 4, locals()

I think the effect would be as if
def f(): ... a = 1
... b = 2
... print 1, locals()
... def __unique_temp():
... a = 2
... c = 3
... print 2, locals()
... def __unique_too():
... print 3, locals()
... __unique_too()
... __unique_temp()
... del __unique_temp
... print 4, locals()
... f() 1 {'a': 1, 'b': 2}
2 {'a': 2, 'c': 3}
3 {}
4 {'a': 1, 'b': 2}

print 3, locals() doesn't show a,b,c in locals() unless you use them
somehow in that scope, e.g.,
def f(): ... a = 1
... b = 2
... print 1, locals()
... def __unique_temp():
... a = 2
... c = 3
... print 2, locals()
... def __unique_too():
... print 3, locals(), (a,b,c) # force references for locals()
... __unique_too()
... __unique_temp()
... del __unique_temp
... print 4, locals()
... f() 1 {'a': 1, 'b': 2}
2 {'a': 2, 'c': 3, 'b': 2}
3 {'a': 2, 'c': 3, 'b': 2} (2, 2, 3)
4 {'a': 1, 'b': 2}

Of course, locals() does not include globals, even though they're
referenced and visible: b 'global b' def bar(): ... print locals(), b
... bar()

{} global b

The trouble with this is that bindings created in __unique_too all get thrown away,
and you wouldn't want that limitation. So I proposed specifying the (re)bindable names
in a parenthesized list with the let, like "let(k, q, w): ..." so that those names
would be (re)bindable in the same scope as the let(...): statement.

As an extension, I also proposed optionally binding __unique_temp to a specified name
and not calling it automatically, instead of the automatic call and del.

That provides new ways to factor updates to local namespaces into local functions
with selective write-through (bind/rebind) to local names. E.g.,

# define case blocks for switch
# better sugar later, this is to demo functinality ;-)
#a
let(x):
k = 123
in foo:
x = k
#b
let(x, y):
q = 456
from math import pi as r
in bar:
x = q
y=r # extra binding created if bar is called
#c
let(x):in baz:x=789 # most compact form, where nothing in the let clause

switch = dict(a=foo, b=bar, c=baz)

Now you can update local bindings with a case switch:
x = 0
case = 'b'
print x # => 0
switch[case]() # executes bar() in this example, which assigns local x=456 and y=pi
print x # => 456
This spare example is easy to dismiss, but think of foo, bar, and baz as arbitrary sequences of statements
in the local namespace, except you can factor them out as a single named group and invoke them
safely by name(), and have them affect only the local names you specify in the group's let(x, y, ...): spec.

It provides a new way of factoring. As well as things no one has thought of yet ;-)

The other thing to think about is that the let suite could be strictly def-time, which would
provide the opportunity to avoid re-calculating things in functions without abusing default args,
and using the easy closure-variable creation instead. E.g.,

let(foo):
preset = big_calc()
in:
def foo(x):
return x * preset

(This "in:" has no "in xxx:" name, so the effect is immediate execution of the anonymously
defined function, which writes through to foo with the def, as permitted by let(foo):).

Problems? (Besides NIH, which I struggle with regularly, and had to overcome to accept Tim's
starting point in this ;-)

Regards,
Bengt Richter
Jul 18 '05 #45

P: n/a
Bengt Richter wrote:
Problems? (Besides NIH, which I struggle with regularly, and had to overcome to accept Tim's
starting point in this ;-)


The ideas regarding creating blocks whose name bindings affect a different scope
are certainly interesting (and relevant to the 'using' out-of-order execution
syntax as well).

Out-of-order execution appeals to me, but the ability to flag 'hey, this is just
setup for something I'm doing later' might be a reasonable alternative
(particularly with the affected names highlighted on the first line). As Jeff
pointed out, it would be significantly less surprising for those encountering
the construct for the first time. Folding code editors would be able to keep the
setup clause out of the way if you really wanted to hide it.

On the other hand, it might be feasible to construct a virtually identical
out-of-order two suite syntax, similar to the mathematical phrasing "let f =
c/lambda where f is the frequency, c is the speed of light and lambda is the
wavelength". Either way, you've convinced me that two suites (and a new compound
statement), as well as specifying which names can be rebound in the containing
scope, is a better way to go than trying to mess with the definition of Python
statements.

On keywords, while 'let' is nice for assignments, I find it just doesn't parse
properly when I put function or class definitions in the clause. So, I'll swap
it for 'use' in the examples below. The statement could then be read "use these
outer bindable names, and this additional code, in this suite". YMMV, naturally.

Let's consider some of the examples given for 'where' using an in-order let/in
type syntax (the examples only bind one name at a time, but would allow multiple
names):

# Anonymous functions
use res:
def f(x):
d = {}
exec x in d
return d
in:
res = [f(i) for i in executable]

# Declaring properties
class C(object):
use x:
def get(self):
print "Demo default"
def set(self, value):
print "Demo default set"
in:
x = property(get, set)

# Design by contract
use foo:
def pre():
pass
def post():
pass
in:
@dbc(pre, post)
def foo():
pass

# Singleton classes
use C:
class _C:
pass
in:
C = _C()

# Complex default values
use f:
def default():
return "Demo default"
in:
def f(x=default()):
pass

They actually read better than I expected. Nicely, the semantics of this form of
the syntax *can* be articulated cleanly with current Python:

use <names>: <use-suite>
in: <in-suite>

as equivalent to:

def __use_stmt():
<use-suite>
def _in_clause():
<in-suite>
return <names>
return _in_clause()
__use_stmt_args = {}
<names> = __use_stmt()
del __use_stmt

Those semantics don't allow your switch statement example, though, since it
doesn't use any magic to write to the outer scope - it's just a normal return
and assign.

However, I don't think starting with these semantics would *preclude* adding the
ability to name the second block at a later date, and make the name rebinding
part of executing that block - the standard usage doesn't really care *how* the
names in the outer scope get bound, just so long as they do. Whether I think
that's a good idea or not is an entirely different question :)

Another aspect to consider is whether augmented assignment operations in the
inner-scopes should work normally - if so, it would be possible to alter the
semantics to include passing the existing values as arguments to the inner scopes.

Moving on to considering a two-suite out-of-order syntax, this would have
identical semantics to the above, but a syntax that might look something like:

as <names>: <in-suite>
using: <use-suite>

# Anonymous functions
as res:
res = [f(i) for i in executable]
using:
def f(x):
d = {}
exec x in d
return d

# Declaring properties
class C(object):
as x:
x = property(get, set)
using:
def get(self):
print "Demo default"
def set(self, value):
print "Demo default set"

# Design by contract
as foo:
@dbc(pre, post)
def foo():
pass
using:
def pre():
pass
def post():
pass

# Singleton classes
as C:
C = _C()
using:
class _C:
pass

# Complex default values
as f:
def f(x=default()):
pass
using:
def default():
return "Demo default"

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #46

P: n/a
Nick Coghlan wrote:
as equivalent to:

def __use_stmt():
<use-suite>
def _in_clause():
<in-suite>
return <names>
return _in_clause()
__use_stmt_args = {}
<names> = __use_stmt()
del __use_stmt


The more I think about this return-based approach, the less I like it. It could
probably be made to work, but it just feels like a kludge to work around the
fact that the only mechanisms available for altering the bindings of local names
are assignment and definition statements.

For class namespaces, getattr(), setattr() and delattr() work a treat, and
globals() works fine for module level name binding.

locals() is an unfortunate second class citizen, since it writes to it aren't
propagated back to the executing frame. Programmatic interrogation of locals is
fine, but update is impossible.

What would be interesting is if locals() returned a dictionary whose __setitem__
method invoked PyFrame_LocalsToFast on the relevant frame, instead of a vanilla
dictionary as it does now.

Then locals()["x"] = foo would actually work properly.

Notice that you can get this effect today, by using exec to force invocation of
PyFrame_LocalsToFast:

Py> def f():
.... n = 1
.... def g(outer=locals()):
.... outer["n"] += 1
.... g() # Does not affect n
.... print n
.... exec "g()" # DOES affect n
.... print n
....
Py> f()
1
2

(The call to g() has to be inside the exec statement, since the exec statement
evaluation starts with a call to PyFrame_FastToLocals).

Assuming a writeable locals(), the semantics for the normal case are given by:
============
def __use_stmt(__outer):
<use-suite>
<in-suite>
__inner = locals()
for name in <names>:
__outer[name] = __inner[name]

__use_stmt(locals())
del __use_stmt
============

And for the 'delayed execution' case:
============
def __named_use_stmt(__outer):
<use-suite>
def __delayed_block():
<in-suite>
__inner = locals()
for name in <names>:
__outer[name] = __inner[name]

return __delayed_block

<in-name> = __named_use_stmt(locals())
del __named_use_stmt
============

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #47

P: n/a
Nick Coghlan wrote:
# Anonymous functions
use res:
def f(x):
d = {}
exec x in d
return d
in:
res = [f(i) for i in executable]


as for me, I found construction "use <name>:" unobvious and confusing.
Also there is great possibility to forget some of variables names.

I think that syntax

<block>
where:
<block>

is more obvious. (and we already have defined semantics for it)

we have two problems, that we try to solve
1) create method to nest scopes
2) create method to reverse execution order for better readability

"using:" solves both at once.
but your "use ... in ..." syntax shows, that you want to be able to
solve 1) independently i.e. create nested scope without reversing
execution order.

so, I can suggest one more keyword "do:", which will create nested
scope, just as "def f(): ... ; f()" do (and that could be just syntaxic
sugar for it.

so "use ... in ..." would look the following way:

do:
res = [f(i) for i in executable]
#some more equations here
using:
def f(x):
d = {}
exec x in d
return d

that seems good for me. of course if you want to return something from
the nest scope you must show that variable is from parent scope.

// while writing that I realized that it's too complex to be implemented
in python in that way. consider it as some type of brainstorming.
Jul 18 '05 #48

This discussion thread is closed

Replies have been disabled for this discussion.