python3: 'where' keyword

Discussion in 'Python' started by Andrey Tatarinov, Jan 7, 2005.

  1. 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.
    Andrey Tatarinov, Jan 7, 2005
    #1
    1. Advertising

  2. 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
    Steven Bethard, Jan 7, 2005
    #2
    1. Advertising

  3. 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
    Steven Bethard, Jan 7, 2005
    #3
  4. Andrey Tatarinov

    Donn Cave Guest

    In article <>,
    Steven Bethard <> 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,
    Donn Cave, Jan 7, 2005
    #4
  5. Andrey Tatarinov

    AdSR Guest

    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
    AdSR, Jan 7, 2005
    #5
  6. Andrey Tatarinov

    Paul Rubin Guest

    Donn Cave <> 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.
    Paul Rubin, Jan 7, 2005
    #6
  7. Andrey Tatarinov

    Nick Coghlan Guest

    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 | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
    Nick Coghlan, Jan 8, 2005
    #7
  8. Andrey Tatarinov

    Paul Rubin Guest

    Nick Coghlan <> 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.
    Paul Rubin, Jan 8, 2005
    #8
  9. Andrey Tatarinov

    Nick Coghlan Guest

    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 | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
    Nick Coghlan, Jan 8, 2005
    #9
  10. Andrey Tatarinov

    Nick Coghlan Guest

    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 | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
    Nick Coghlan, Jan 8, 2005
    #10
  11. Andrey Tatarinov

    Guest


    > 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
    , Jan 8, 2005
    #11
  12. Andrey Tatarinov

    Carl Banks Guest

    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
    Carl Banks, Jan 8, 2005
    #12
  13. Andrey Tatarinov

    Nick Coghlan Guest

    Re: python3: accessing the result of 'if'

    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 | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
    Nick Coghlan, Jan 8, 2005
    #13
  14. Andrey Tatarinov

    Paul Rubin Guest

    Re: python3: accessing the result of 'if'

    Nick Coghlan <> 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.
    Paul Rubin, Jan 8, 2005
    #14
  15. Andrey Tatarinov

    AdSR Guest

    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
    AdSR, Jan 8, 2005
    #15
  16. Andrey Tatarinov

    Paul Rubin Guest

    AdSR <> 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.
    Paul Rubin, Jan 8, 2005
    #16
  17. On Sat, 08 Jan 2005 16:42:16 +1000, Nick Coghlan <> 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
    Bengt Richter, Jan 8, 2005
    #17
  18. 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.
    Andrey Tatarinov, Jan 8, 2005
    #18
  19. 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
    Andrey Tatarinov, Jan 8, 2005
    #19
  20. 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
    =?iso-8859-1?B?QW5kcuk=?=, Jan 8, 2005
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andrey Tatarinov

    Python3: on removing map, reduce, filter

    Andrey Tatarinov, Jan 9, 2005, in forum: Python
    Replies:
    18
    Views:
    1,213
    Steven Bethard
    Jan 11, 2005
  2. Replies:
    37
    Views:
    830
    Steve Holden
    Jan 14, 2005
  3. Replies:
    6
    Views:
    441
    Peter Otten
    May 10, 2007
  4. Hamilton, William

    RE: keyword checker - keyword.kwlist

    Hamilton, William, May 10, 2007, in forum: Python
    Replies:
    4
    Views:
    343
  5. Andrew Berg
    Replies:
    0
    Views:
    322
    Andrew Berg
    Jun 16, 2012
Loading...

Share This Page