Re: Ifs and assignments

Discussion in 'Python' started by John Allsup, Jan 2, 2014.

  1. John Allsup

    John Allsup Guest

    The point of my original post was that, whilst C's
    if( x = 2 ) { do something }
    and
    if( x == 2 ) { do something }
    are easy to confuse, and a source of bugs, having a construct like follows:

    if x == 2:
    do something # what happens at present
    if testFunc() as x:
    do something with x

    using the 'as' syntax that appears with 'with' and 'except', would allow
    for the advantages of C style assignments in conditionals but without
    the easy confusion, since here the syntax is significantly different
    between assignment and equality testing (rather than a character apart
    as happens with C).

    This occurs further down in my original post (past the point where you
    inserted your reply).

    Another post suggested a workaround by defining a 'pocket' class, for
    which I am grateful.

    John


    On 02/01/2014 19:27, Gary Herron wrote:
    > On 01/02/2014 09:20 AM, John Allsup wrote:
    >> Hi,
    >>
    >> This is my debut on this list.
    >>
    >> In many languages, such as C, one can use assignments in conditionals
    >> and expressions. The most common, and useful case turns up when you
    >> have if/else if/else if/else constructs. Consider the following
    >> non-working pseudoPython.
    >>
    >> import re
    >> r1 = re.compile("hello (\d)")
    >> r2 = re.compile("world([!?])")
    >>
    >> w = "hello world!"
    >>
    >> if m = r1.search(w):

    >
    > This kind of thing in C/C+ has always been the source of much confusion
    > and potential errors, because the construct is so similar to an "=="
    > test. Python does not replicate this potential for confusion. Instead,
    > we use two lines of code, an assignment and then the test. If you find
    > that extra line of code inconvenient than at least you can take comfort
    > in the fact that it is clearer code. If you are still not convinced,
    > ... then sorry, that's just the way Python is.
    >
    > Gary Herron
    >
    >
    >> handleMatch1(m)
    >> elif m = r2.search(w):
    >> handleMatch2(m)
    >> else:
    >> print("No match")
    >>
    >> If the regular expressions are complex, running them multiple times
    >> (once to test, another to capture groups) isn't ideal. On the other
    >> hand, at present, one has to either do:
    >>
    >> m = r1.search(w)
    >> if m:
    >> handleMatch1(m)
    >> else:
    >> m = r2.search(w)
    >> if m:
    >> handleMatch2(m)
    >> else:
    >> print("No match")
    >>
    >> if not running unnecessary matches, yet capturing groups in the event
    >> of a successful match, is what is desired.
    >>
    >> If there are multiple tests, the indentation gets silly. This arises
    >> because having removed the ability to assign in an expression, there
    >> is no way to save the result of a function call that is used in a
    >> conditional at all.
    >>
    >> I am aware that this facility in C is a source of bugs, = being only a
    >> typo away from the more common ==. With exceptions and contexts, we
    >> have:
    >>
    >> with open("file") as f:
    >> doSomethingWith(f)
    >>
    >> try:
    >> trySomething()
    >> except SomethingRandomGoingWrong as e:
    >> lookAtException(e)
    >>
    >> What I am wondering is why not use a similar syntax with if, so that
    >> one could do
    >>
    >> if r1.search(w) as m:
    >> g = m.groups()
    >> print(g[1])
    >>
    >> This would remove the risk of errors by typos since the syntax for
    >> equality testing (if x == y:) is completely different from that for
    >> assigning in a conditional (which would look like 'if y as x:'
    >>
    >> Related would be to have Nonetype work with contexts such that
    >>
    >> with None as x:
    >> doStuff(x)
    >>
    >> would do nothing. This would allow things like:
    >>
    >> with maybeGetSomething as x:
    >> doStuff(x)
    >>
    >> to call doStuff(x) within a context of maybeGetSomething returns
    >> something, or do nothing if nothing is returned. (Adding an else-like
    >> keyword to with, or possibly using else in that context, would allow
    >> one to process a non-None object if returned, or else do something in
    >> response to a None object being returned by the maybeGetSomething.)
    >>
    >> Just a thought.
    >>
    >> Or what is the current 'Pythonic' way to do something like:
    >>
    >> if x = func1():
    >> do1(x)
    >> elif x = func2():
    >> do2(x)
    >> elif x = func3():
    >> do3(x)
    >> elif x = func4():
    >> do4(x)
    >> else:
    >> do5()
    >>
    >> where each of func1,func2,func3,func4 have side effects so that func2
    >> is tested if and only if func1 returns a false value, func1 must be
    >> called only once, and what is returned from func1 must be available to
    >> the code inside the if block?
    >>
    >>
    >> John
    >>

    >
     
    John Allsup, Jan 2, 2014
    #1
    1. Advertising

  2. John Allsup

    Roy Smith Guest

    In article <>,
    John Allsup <> wrote:

    > if testFunc() as x:
    > do something with x


    +1

    The most common place I wish for an atomic "test and assign" is with
    regexes, as in your examples. This would be so much nicer than what we
    have to do now:

    if re.match(string) as m:
    print m.group(0)

    The analogy to

    except SomeError as ex:

    is very clear. They are both "Perform some action, capture the result,
    do some test on it, and then make that captured value available bound to
    a name".
     
    Roy Smith, Jan 2, 2014
    #2
    1. Advertising

  3. On Fri, Jan 3, 2014 at 10:36 AM, Roy Smith <> wrote:
    > The most common place I wish for an atomic "test and assign" is with
    > regexes, as in your examples. This would be so much nicer than what we
    > have to do now:
    >
    > if re.match(string) as m:
    > print m.group(0)


    Here's a crazy idea. Suppose we have a "sticky falseness" that can
    quietly propagate through an expression the way a NaN can... then we
    could just float that right through the .group() call.

    class truth:
    def __new__(cls, x):
    if x: return x
    return object.__new__(cls)
    def __bool__(self):
    return False
    def __getattr__(self, name):
    return self
    def __call__(self, *args, **kwargs):
    return self
    def __repr__(self):
    return repr(False)

    Pass any object through truth() and it'll either stay the same (if
    it's true) or become this object (if it's false). You can then carry
    on with other method calls, and they'll all happily return false.

    result = (
    truth(re1.match(string)).group(0) or
    truth(re2.match(string)).group(0) or
    truth(re3.match(string)).group(0) or
    default_value
    )

    (I'm not sure if I'm using __new__ correctly; I've never actually done
    it in production code, and the info I found online was mainly Py2
    examples. Should that be done with super(), or is that applicable only
    once there's an actual instance with a real MRO?)

    I've given the class a lower-case first letter as I'm basically using
    this as a function. If this were ever to be considered for the
    standard library I would expect to see that aspect of it heavily
    bikeshedded, so I'm not too concerned about the details.

    In a spirit of full disclosure, I must confess that the idea came from
    Pike, where there's a variant member-lookup operator that will happily
    return false from false rather than throwing an exception. :)

    ChrisA
     
    Chris Angelico, Jan 3, 2014
    #3
  4. On Fri, Jan 3, 2014 at 11:06 AM, Chris Angelico <> wrote:
    > Pass any object through truth() and it'll either stay the same (if
    > it's true) or become this object (if it's false). You can then carry
    > on with other method calls, and they'll all happily return false.
    >
    > result = (
    > truth(re1.match(string)).group(0) or
    > truth(re2.match(string)).group(0) or
    > truth(re3.match(string)).group(0) or
    > default_value
    > )


    Oh, just thought of a possible snag. Since an empty string comes up as
    false, this exact notation would fail if the re can match nothing. But
    you probably know if it's possible for that to happen, so don't use
    this simple short-hand. :)

    ChrisA
     
    Chris Angelico, Jan 3, 2014
    #4
  5. John Allsup

    Ethan Furman Guest

    On 01/02/2014 04:06 PM, Chris Angelico wrote:
    >
    > Here's a crazy idea. Suppose we have a "sticky falseness" that can
    > quietly propagate through an expression the way a NaN can... then we
    > could just float that right through the .group() call.
    >
    > class truth:
    > def __new__(cls, x):
    > if x: return x
    > return object.__new__(cls)
    > def __bool__(self):
    > return False
    > def __getattr__(self, name):
    > return self
    > def __call__(self, *args, **kwargs):
    > return self
    > def __repr__(self):
    > return repr(False)
    >
    > Pass any object through truth() and it'll either stay the same (if
    > it's true) or become this object (if it's false). You can then carry
    > on with other method calls, and they'll all happily return false.


    An interesting idea. You'd need to add (at least) __getitem__, and I'll
    probably call it `maybe`, myself. ;)


    > (I'm not sure if I'm using __new__ correctly; I've never actually done
    > it in production code, and the info I found online was mainly Py2
    > examples. Should that be done with super(), or is that applicable only
    > once there's an actual instance with a real MRO?)


    I haven't tested it, but your __new__ looks fine. The only thing you
    lose by not calling super() is the inability for cooperative multiple
    inheritance, except as the ultimate base class.

    --
    ~Ethan~
     
    Ethan Furman, Jan 3, 2014
    #5
  6. On Fri, Jan 3, 2014 at 3:16 PM, Ethan Furman <> wrote:
    > On 01/02/2014 04:06 PM, Chris Angelico wrote:
    >>
    >>
    >> Here's a crazy idea. Suppose we have a "sticky falseness" that can
    >> quietly propagate through an expression the way a NaN can... then we
    >> could just float that right through the .group() call.
    >>
    >> class truth:

    >
    > An interesting idea. You'd need to add (at least) __getitem__, and I'll
    > probably call it `maybe`, myself. ;)


    I was going for something like bool(). If you pass something through
    bool(), you get either True or False; if you pass something through
    this, you get either itself or something that acts like False.

    >> (I'm not sure if I'm using __new__ correctly; I've never actually done
    >> it in production code, and the info I found online was mainly Py2
    >> examples. Should that be done with super(), or is that applicable only
    >> once there's an actual instance with a real MRO?)

    >
    > I haven't tested it, but your __new__ looks fine. The only thing you lose
    > by not calling super() is the inability for cooperative multiple
    > inheritance, except as the ultimate base class.


    Is it possible to have multiple inheritance at this point, though? I
    get a class argument, not an instance, because there isn't an
    instance.

    ChrisA
     
    Chris Angelico, Jan 3, 2014
    #6
    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. Markus Dehmann
    Replies:
    8
    Views:
    2,100
    bartek
    Jun 2, 2004
  2. charlie

    Nested ifs and speed.

    charlie, Jul 24, 2006, in forum: C Programming
    Replies:
    11
    Views:
    570
    BubbaGump
    Jul 26, 2006
  3. John Allsup

    Ifs and assignments

    John Allsup, Jan 2, 2014, in forum: Python
    Replies:
    0
    Views:
    99
    John Allsup
    Jan 2, 2014
  4. Dennis Lee Bieber

    Re: Ifs and assignments

    Dennis Lee Bieber, Jan 3, 2014, in forum: Python
    Replies:
    8
    Views:
    81
    Mark Lawrence
    Jan 3, 2014
  5. Terry Reedy

    Re: Ifs and assignments

    Terry Reedy, Jan 3, 2014, in forum: Python
    Replies:
    0
    Views:
    86
    Terry Reedy
    Jan 3, 2014
Loading...

Share This Page