C-like assignment expression?

Discussion in 'Python' started by boblatest@googlemail.com, May 21, 2008.

  1. Guest

    Hello,

    I have an if-elif chain in which I'd like to match a string against
    several regular expressions. Also I'd like to use the match groups
    within the respective elif... block. The C-like idiom that I would
    like to use is this:

    if (match = my_re1.match(line):
    # use match
    elsif (match = my_re2.match(line)):
    # use match
    elsif (match = my_re3.match(line))
    # use match

    ....buy this is illegal in python. The other way is to open up an else:
    block in each level, do the assignment and then the test. This
    unneccessarily leads to deeper and deeper nesting levels which I find
    ugly. Just as ugly as first testing against the RE in the elif: clause
    and then, if it matches, to re-evaluate the RE to access the match
    groups.

    Thanks,
    robert
    , May 21, 2008
    #1
    1. Advertising

  2. wrote:

    > Hello,
    >
    > I have an if-elif chain in which I'd like to match a string against
    > several regular expressions. Also I'd like to use the match groups
    > within the respective elif... block. The C-like idiom that I would
    > like to use is this:
    >
    > if (match = my_re1.match(line):
    > # use match
    > elsif (match = my_re2.match(line)):
    > # use match
    > elsif (match = my_re3.match(line))
    > # use match
    >
    > ...buy this is illegal in python. The other way is to open up an else:
    > block in each level, do the assignment and then the test. This
    > unneccessarily leads to deeper and deeper nesting levels which I find
    > ugly. Just as ugly as first testing against the RE in the elif: clause
    > and then, if it matches, to re-evaluate the RE to access the match
    > groups.


    This might help:

    -----------
    s = "foo"

    class Tester(object):

    def __call__(self, pattern):
    self.m = re.match(pattern, s)
    return self.m is not None

    def __getattr__(self, name):
    return getattr(self.m, name)

    test = Tester()

    if test("bar"):
    print "wrong"
    elif test("foo"):
    print "right"
    -------------


    Diez
    Diez B. Roggisch, May 21, 2008
    #2
    1. Advertising

  3. wrote:
    > I have an if-elif chain in which I'd like to match a string against
    > several regular expressions. Also I'd like to use the match groups
    > within the respective elif... block. The C-like idiom that I would
    > like to use is this:
    >
    > if (match = my_re1.match(line):
    > # use match
    > elsif (match = my_re2.match(line)):
    > # use match
    > elsif (match = my_re3.match(line))
    > # use match
    >
    > ...buy this is illegal in python. The other way is to open up an else:
    > block in each level, do the assignment and then the test. This
    > unneccessarily leads to deeper and deeper nesting levels which I find
    > ugly.


    How about this (untested) code:

    for re in (re1, re2, re3):
    match = re.match(line)
    if match:
    # use it

    This requires that "use it" means the same for each regular expression
    though...

    Uli

    --
    Sator Laser GmbH
    Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
    Ulrich Eckhardt, May 21, 2008
    #3
  4. a écrit :
    > Hello,
    >
    > I have an if-elif chain in which I'd like to match a string against
    > several regular expressions. Also I'd like to use the match groups
    > within the respective elif... block. The C-like idiom that I would
    > like to use is this:
    >
    > if (match = my_re1.match(line):
    > # use match
    > elsif (match = my_re2.match(line)):
    > # use match
    > elsif (match = my_re3.match(line))
    > # use match


    <ot>
    Isn't it the third or fourth time this very same question pops up here ?
    Starts to look like a FAQ.
    </ot>

    The canonical solution is to iterate over a list of expression,function
    pairs, ie:

    def use_match1(match):
    # code here

    def use_match2(match):
    # code here

    def use_match3(match):
    # code here

    for exp, func in [
    (my_re1, use_match1),
    (my_re2, use_match2),
    (my_re3, use_match3)
    ]:
    match = exp.match(line)
    if match:
    func(match)
    break


    The alternate solution is Diez's Test object.

    HTH
    Bruno Desthuilliers, May 21, 2008
    #4
  5. Bruno Desthuilliers <>
    writes:

    > The canonical solution is to iterate over a list of
    > expression,function pairs, ie:


    Although that solution is pretty, it is not the canonical solution
    because it doesn't cover the important case of "if" bodies needing to
    access common variables in the enclosing scope. (This will be easier
    in Python 3 with 'nonlocal', though.) The snippet posted by Diez is
    IMHO closer to a canonical solution to this FAQ.
    Hrvoje Niksic, May 21, 2008
    #5
  6. Guest

    On May 21, 1:47 pm, Hrvoje Niksic <> wrote:

    > Although that solution is pretty, it is not the canonical solution
    > because it doesn't cover the important case of "if" bodies needing to
    > access common variables in the enclosing scope. (This will be easier
    > in Python 3 with 'nonlocal', though.) The snippet posted by Diez is
    > IMHO closer to a canonical solution to this FAQ.


    Hello everybody,

    thanks for the various answers. I'm actually pretty puzzled because I
    expected to see some obvious solution that I just hadn't found before.
    In general I find Python more elegant and syntactically richer than C
    (that's where I come from), so I didn't expect the solutions to be a
    lot more verbose and/or ugly (no offense) than the original idea which
    would have worked if Python's assignment statement would double as
    expression, as in C.

    Thanks again,
    robert

    PS: Since I'm testing only three REs, and I only need the match
    results from one of them, I just re-evaluate that one.
    , May 21, 2008
    #6
  7. Guest

    On May 21, 3:12 pm, ""
    <> wrote:
    > On May 21, 1:47 pm, Hrvoje Niksic <> wrote:
    >
    > > Although that solution is pretty, it is not the canonical solution
    > > because it doesn't cover the important case of "if" bodies needing to
    > > access common variables in the enclosing scope. (This will be easier
    > > in Python 3 with 'nonlocal', though.) The snippet posted by Diez is
    > > IMHO closer to a canonical solution to this FAQ.

    >
    > Hello everybody,
    >
    > thanks for the various answers. I'm actually pretty puzzled because I
    > expected to see some obvious solution that I just hadn't found before.
    > In general I find Python more elegant and syntactically richer than C
    > (that's where I come from), so I didn't expect the solutions to be a
    > lot more verbose and/or ugly (no offense) than the original idea which
    > would have worked if Python's assignment statement would double as
    > expression, as in C.
    >
    > Thanks again,
    > robert
    >
    > PS: Since I'm testing only three REs, and I only need the match
    > results from one of them, I just re-evaluate that one.


    Is it really a lot to change to have it

    if my_re1.match(line):
    match = my_re1.match(line)
    elseif my_re2.match(line):
    match = my_re2.match(line)
    elseif my_re3.match(line):
    match = my_re3.match(line)

    ?

    That reads clearly to me...
    , May 21, 2008
    #7
  8. wrote:

    > On May 21, 1:47 pm, Hrvoje Niksic <> wrote:
    >
    >> Although that solution is pretty, it is not the canonical solution
    >> because it doesn't cover the important case of "if" bodies needing to
    >> access common variables in the enclosing scope. (This will be easier
    >> in Python 3 with 'nonlocal', though.) The snippet posted by Diez is
    >> IMHO closer to a canonical solution to this FAQ.

    >
    > Hello everybody,
    >
    > thanks for the various answers. I'm actually pretty puzzled because I
    > expected to see some obvious solution that I just hadn't found before.
    > In general I find Python more elegant and syntactically richer than C
    > (that's where I come from), so I didn't expect the solutions to be a
    > lot more verbose and/or ugly (no offense) than the original idea which
    > would have worked if Python's assignment statement would double as
    > expression, as in C.


    Well, it's a design-decision - and I'm pretty ok with it being a bit verbose
    here - as it prevents a *great* deal of programming errors that would
    otherwise happen from accidentally writing a = b where a == b was meant.

    One could argue that regular expressions - which seem to be THE case where
    it bugs people - should offer a standard way that essentially works as my
    solution - by keeping state around, making series of tests easier.


    Diez
    Diez B. Roggisch, May 21, 2008
    #8
  9. wrote:

    > On May 21, 3:12 pm, ""
    > <> wrote:
    >> On May 21, 1:47 pm, Hrvoje Niksic <> wrote:
    >>
    >> > Although that solution is pretty, it is not the canonical solution
    >> > because it doesn't cover the important case of "if" bodies needing to
    >> > access common variables in the enclosing scope. (This will be easier
    >> > in Python 3 with 'nonlocal', though.) The snippet posted by Diez is
    >> > IMHO closer to a canonical solution to this FAQ.

    >>
    >> Hello everybody,
    >>
    >> thanks for the various answers. I'm actually pretty puzzled because I
    >> expected to see some obvious solution that I just hadn't found before.
    >> In general I find Python more elegant and syntactically richer than C
    >> (that's where I come from), so I didn't expect the solutions to be a
    >> lot more verbose and/or ugly (no offense) than the original idea which
    >> would have worked if Python's assignment statement would double as
    >> expression, as in C.
    >>
    >> Thanks again,
    >> robert
    >>
    >> PS: Since I'm testing only three REs, and I only need the match
    >> results from one of them, I just re-evaluate that one.

    >
    > Is it really a lot to change to have it
    >
    > if my_re1.match(line):
    > match = my_re1.match(line)
    > elseif my_re2.match(line):
    > match = my_re2.match(line)
    > elseif my_re3.match(line):
    > match = my_re3.match(line)
    >
    > ?
    >
    > That reads clearly to me...


    And wastes time. regular expressions can become expensive to match - doing
    it twice might be hurtful.

    Diez
    Diez B. Roggisch, May 21, 2008
    #9
  10. Guest

    >
    > And wastes time. regular expressions can become expensive to match - doing
    > it twice might be hurtful.
    >
    > Diez


    match = (my_re1.match(line) or my_re2.match(line)) or
    my_re3.match(line)

    ?
    , May 21, 2008
    #10
  11. wrote:

    >>
    >> And wastes time. regular expressions can become expensive to match -
    >> doing it twice might be hurtful.
    >>
    >> Diez

    >
    > match = (my_re1.match(line) or my_re2.match(line)) or
    > my_re3.match(line)


    How do you know *which* of the three has matched then?

    Diez
    Diez B. Roggisch, May 21, 2008
    #11
  12. Guest

    On May 21, 4:09 pm, "Diez B. Roggisch" <> wrote:
    > wrote:
    >
    > >> And wastes time. regular expressions can become expensive to match -
    > >> doing it twice might be hurtful.

    >
    > >> Diez

    >
    > > match = (my_re1.match(line) or my_re2.match(line)) or
    > > my_re3.match(line)

    >
    > How do you know *which* of the three has matched then?
    >
    > Diez


    Depends if the OP wants to know that...
    , May 21, 2008
    #12
  13. inhahe Guest

    one of the few things i miss from C is being able to use assignment in
    expressions. that's the only thing, really.
    also there's no switch/case, you have to use a dictionary of functions
    instead, although i rarely need that, usually i just use elif.

    <> wrote in message
    news:...
    > On May 21, 1:47 pm, Hrvoje Niksic <> wrote:
    >
    >> Although that solution is pretty, it is not the canonical solution
    >> because it doesn't cover the important case of "if" bodies needing to
    >> access common variables in the enclosing scope. (This will be easier
    >> in Python 3 with 'nonlocal', though.) The snippet posted by Diez is
    >> IMHO closer to a canonical solution to this FAQ.

    >
    > Hello everybody,
    >
    > thanks for the various answers. I'm actually pretty puzzled because I
    > expected to see some obvious solution that I just hadn't found before.
    > In general I find Python more elegant and syntactically richer than C
    > (that's where I come from), so I didn't expect the solutions to be a
    > lot more verbose and/or ugly (no offense) than the original idea which
    > would have worked if Python's assignment statement would double as
    > expression, as in C.
    >
    > Thanks again,
    > robert
    >
    > PS: Since I'm testing only three REs, and I only need the match
    > results from one of them, I just re-evaluate that one.
    inhahe, May 21, 2008
    #13
  14. wrote:

    > On May 21, 4:09 pm, "Diez B. Roggisch" <> wrote:
    >> wrote:
    >>
    >> >> And wastes time. regular expressions can become expensive to match -
    >> >> doing it twice might be hurtful.

    >>
    >> >> Diez

    >>
    >> > match = (my_re1.match(line) or my_re2.match(line)) or
    >> > my_re3.match(line)

    >>
    >> How do you know *which* of the three has matched then?
    >>
    >> Diez

    >
    > Depends if the OP wants to know that...


    Well, in *general* one wants that. So as a general-purpose solution this is
    certainly *not* the way to go.

    Diez
    Diez B. Roggisch, May 21, 2008
    #14
  15. Guest

    On May 21, 4:57 pm, "inhahe" <> wrote:
    > one of the few things i miss from C is being able to use assignment in
    > expressions. that's the only thing, really.
    > also there's no switch/case, you have to use a dictionary of functions
    > instead, although i rarely need that, usually i just use elif.


    One thing I hate from C is the assignment in expressions...Forcing
    myself to write
    0 == Something
    rather than
    Something == 0
    just to make sure I was mistakenly assigning values in statements is
    annoying, it ruins the ease of reading.

    I kind of agree with the select:case, but I think a key issue is how
    to implement it. Elif is reasonable for now.

    Diez, true I guess, but then we haven't seen what these expressions
    are, and why there has to be three.
    , May 21, 2008
    #15
  16. Paul McGuire Guest

    On May 21, 9:09 am, "Diez B. Roggisch" <> wrote:
    > wrote:
    >
    > >> And wastes time. regular expressions can become expensive to match -
    > >> doing it twice might be hurtful.

    >
    > >> Diez

    >
    > > match = (my_re1.match(line) or my_re2.match(line)) or
    > > my_re3.match(line)

    >
    > How do you know *which* of the three has matched then?
    >
    > Diez


    Since the OP is processing alternative regexp's, he may be drifting
    close to parsing territory. Here is a pyparsing example showing how
    to match one of 'n' alternatives, and then apply functional logic
    depending on which expression was matched. This example actually
    shows 4 ways to address this question (in roughly increasing order of
    OO-ness):
    - explicit if/elif/... test on the name of the specific match to see
    which alternative matched
    - more Pythonic dispatch using a dict of names and corresponding
    expression processing functions
    - parse-time processing using pyparsing parse actions
    - parse actions invoke class constructors, to return expression-
    specific objects

    -- Paul


    from pyparsing import oneOf, Combine, Optional, Word, \
    alphas, nums, alphanums, QuotedString

    # define basic expressions
    sign = oneOf("+ -")
    integer = Combine(Optional(sign) + Word(nums))
    real = Combine(Optional(sign) + Word(nums) + "." +
    Optional(Word(nums)))
    name = Word(alphas,alphanums) | QuotedString("'")

    # define alternates with results names
    item = real("real") | integer("integer") | name("name")

    print "\nUse results names to determine which pattern matched"
    for it in item.searchString("abc 123 -3.14 'phase of the moon'"):
    if it.getName() == "real":
    print "Real:", (float(it[0]))
    elif it.getName() == "integer":
    print "Int:", (int(it[0]))
    else:
    print "String:", it[0]


    print "\nUse dict to dispatch to type-specific functions " \
    "- more Pythonically canonical"
    def processRealItem(it):
    print "Real:", (float(it[0]))

    def processIntegerItem(it):
    print "Int:", (int(it[0]))

    def processNameItem(it):
    print "String:", it[0]

    for it in item.searchString("abc 123 -3.14 'phase of the moon'"):
    {"real" : processRealItem,
    "integer" : processIntegerItem,
    "name" : processNameItem }[it.getName()](it)


    print "\nMove expression-specific logic into parse-time parse actions"
    def convertInt(t):
    return int(t[0])
    def convertReal(t):
    return float(t[0])
    integer.setParseAction(convertInt)
    real.setParseAction(convertReal)
    item = real("real") | integer("integer") | name("name")

    for it in item.searchString("abc 123 -3.14 'phase of the moon'"):
    print "%s: %s %s" % (it.getName(), it[0], type(it[0]))


    print "\nUse class constructors as parse-time parse actions " \
    "- results names no longer needed"
    class IntObject(object):
    def __init__(self,t):
    self.type, self.value = "Int", int(t[0])
    class RealObject(object):
    def __init__(self,t):
    self.type, self.value = "Real", float(t[0])
    class StringObject(object):
    def __init__(self,t):
    self.type, self.value = "String", t[0]
    integer.setParseAction(IntObject)
    real.setParseAction(RealObject)
    name.setParseAction(StringObject)
    item = real | integer | name

    for it in item.searchString("abc 123 -3.14 'phase of the moon'"):
    print "%s: %s (%s)" % (it[0].type, it[0].value,
    it[0].__class__.__name__)


    Prints:

    Use results names to determine which pattern matched
    String: abc
    Int: 123
    Real: -3.14
    String: phase of the moon

    Use dict to dispatch to type-specific functions - more Pythonically
    canonical
    String: abc
    Int: 123
    Real: -3.14
    String: phase of the moon

    Move expression-specific logic into parse-time parse actions
    name: abc <type 'str'>
    integer: 123 <type 'int'>
    real: -3.14 <type 'float'>
    name: phase of the moon <type 'str'>

    Use class constructors as parse-time parse actions - results names no
    longer needed
    String: abc (StringObject)
    Int: 123 (IntObject)
    Real: -3.14 (RealObject)
    String: phase of the moon (StringObject)
    Paul McGuire, May 21, 2008
    #16
  17. Kay Schluehr Guest

    On 21 Mai, 11:38, wrote:
    > Hello,
    >
    > I have an if-elif chain in which I'd like to match a string against
    > several regular expressions. Also I'd like to use the match groups
    > within the respective elif... block. The C-like idiom that I would
    > like to use is this:
    >
    > if (match = my_re1.match(line):
    > # use match
    > elsif (match = my_re2.match(line)):
    > # use match
    > elsif (match = my_re3.match(line))
    > # use match
    >
    > ...buy this is illegal in python. The other way is to open up an else:
    > block in each level, do the assignment and then the test. This
    > unneccessarily leads to deeper and deeper nesting levels which I find
    > ugly. Just as ugly as first testing against the RE in the elif: clause
    > and then, if it matches, to re-evaluate the RE to access the match
    > groups.
    >
    > Thanks,
    > robert


    You are perfectly correct. Pythons design is lacking here IMO. But
    what is your question?
    Kay Schluehr, May 21, 2008
    #17
  18. inhahe Guest

    <> wrote in message
    news:...
    > On May 21, 4:57 pm, "inhahe" <> wrote:
    >> one of the few things i miss from C is being able to use assignment in
    >> expressions. that's the only thing, really.
    >> also there's no switch/case, you have to use a dictionary of functions
    >> instead, although i rarely need that, usually i just use elif.

    >
    > One thing I hate from C is the assignment in expressions...Forcing
    > myself to write
    > 0 == Something
    > rather than
    > Something == 0


    interesting trick, i've never thought of that/seen it
    although if Python implemented it I think it should default to giving
    warnings when you use = in an expression, that way you don't have to worry.

    > just to make sure I was mistakenly assigning values in statements is
    > annoying, it ruins the ease of reading.
    >
    > I kind of agree with the select:case, but I think a key issue is how
    > to implement it. Elif is reasonable for now.
    >
    > Diez, true I guess, but then we haven't seen what these expressions
    > are, and why there has to be three.
    inhahe, May 21, 2008
    #18
  19. inhahe Guest

    >>
    >> One thing I hate from C is the assignment in expressions...Forcing
    >> myself to write
    >> 0 == Something
    >> rather than
    >> Something == 0

    >
    > interesting trick, i've never thought of that/seen it
    > although if Python implemented it I think it should default to giving
    > warnings when you use = in an expression, that way you don't have to
    > worry.
    >


    That introduces complications though, do you want to see a pagefull of
    warnings every time you import a module that uses the ='s?
    You could specify in your python file that you want to suppress that
    warning, but then you'd never know when you used = by accident when you
    meant to use ==.
    anyway i was thinking you could have a second assignment operator to use
    just in expressions, and only allow that. it could be := since some
    languages tend to use that. i wouldn't like it as a general assignment
    operator but assignment in expressions is a special case. also <- or ->.
    C uses -> for functions but I think math/calculators use that for
    assignment.
    inhahe, May 21, 2008
    #19
  20. MRAB Guest

    On May 21, 5:50 pm, "inhahe" <> wrote:
    > >> One thing I hate from C is the assignment in expressions...Forcing
    > >> myself to write
    > >> 0 == Something
    > >> rather than
    > >> Something == 0

    >
    > > interesting trick, i've never thought of that/seen it
    > > although if Python implemented it I think it should default to giving
    > > warnings when you use = in an expression, that way you don't have to
    > > worry.

    >
    > That introduces complications though, do you want to see a pagefull of
    > warnings every time you import a module that uses the ='s?
    > You could specify in your python file that you want to suppress that
    > warning, but then you'd never know when you used = by accident when you
    > meant to use ==.
    > anyway i was thinking you could have a second assignment operator to use
    > just in expressions, and only allow that. it could be := since some
    > languages tend to use that. i wouldn't like it as a general assignment
    > operator but assignment in expressions is a special case. also <- or ->.
    > C uses -> for functions but I think math/calculators use that for
    > assignment.


    My preference would be ?=.

    if match ?= my_re1.match(line):
    # use match
    elif match ?= my_re2.match(line):
    # use match
    elif match ?= my_re3.match(line):
    # use match
    MRAB, May 21, 2008
    #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. Paul Rubin

    assignment expression peeve

    Paul Rubin, Oct 15, 2003, in forum: Python
    Replies:
    47
    Views:
    939
    Terry Reedy
    Oct 21, 2003
  2. Dave Benjamin
    Replies:
    2
    Views:
    335
    Dave Benjamin
    Nov 12, 2003
  3. nagy
    Replies:
    36
    Views:
    978
    Terry Reedy
    Jul 20, 2006
  4. Patrick Kowalzick
    Replies:
    5
    Views:
    456
    Patrick Kowalzick
    Mar 14, 2006
  5. Chris
    Replies:
    34
    Views:
    1,480
Loading...

Share This Page