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.
> 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
> - 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.
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:
> 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
> > - 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.
> 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
> - 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 ;)
Donn Cave <d...@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.
> 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.
Nick Coghlan <ncogh...@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.
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"
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?
> 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.
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:
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.
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
On Sat, 08 Jan 2005 16:42:16 +1000, Nick Coghlan <ncogh...@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 ;-)
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.
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
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
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.
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.
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.
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.