C-like assignment expression?

S

sturlamolden

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.


Assignment expressions is disallowed in Python to protect against a
very common bug in C/C++ programs, the (accidental) confusion of

if (match = my_re1.match(line))

with

if (match == my_re1.match(line))

or vice versa.
 
P

Paddy

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 could use named groups to search for all three patterns at once
like this:


original:

prog1 = re.compile(r'pat1')
prog2 = re.compile(r'pat2')
prog3 = re.compile(r'pat3')
...

Becomes:

prog = re.compile(r'(?P<p1>pat1)|(?P<p2>pat2)|(?P<p3>pat3)')
match = prog.match(line)
for p in 'p1 p2 p3'.split():
if match.groupdict()[p]:
do_something_for_prog(p)


- Paddy.
 
K

Kay Schluehr

Assignment expressions is disallowed in Python to protect against a
very common bug in C/C++ programs, the (accidental) confusion of

if (match = my_re1.match(line))

with

if (match == my_re1.match(line))

or vice versa.

This is just a syntactical issue. But what is the *value* of an
assigment? In Python it is always None: assigments are statements, not
expressions.

However Guido and team have found a *pragmatic* solution for this at
another place:

with open("myFile") as f:
BLOCK

Compare this with a possible syntactical form of an if-statement:

if EXPR as NAME:
BLOCK

This isn't ugly syntax-wise. It's just a bit harder to understand the
semantics of an if-statement. It might read like this:

"Evaluate EXPR and compute bool(EXPR). If this value is True assign
EXPR to NAME and execute BLOCK. Otherwise refuse both assigment and
BLOCK execution."

Maybe assignment can be performed unconditionally as in the C case.
I'm not sure about this.
 
A

Antoon Pardon

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.

But that is an error that occurs because of the specific symbols chosen
to represent an assignment or equality test. At the time python was
first designed, other symbols for assignment were already used for
in other languages, like := and <-

So if preventing errors was the main motivation why not allow an
assignment to be an expression but use a symbol for the assignment
that would prevent those kind of errors?

I find it hard to believe that a design choice like whether or not
to have the assignment behave as an expression or not, was decided
on the ground of a particulare lexical representation of the assignment
symbol.
 
P

Paul McGuire

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

Try this.

-- Paul

class TestValue(object):
"""Class to support assignment and test in single operation"""
def __init__(self,v=None):
self.value = v

"""Add support for quasi-assignment syntax using '<<' in place of
'='."""
def __lshift__(self,other):
self.value = other
return bool(self.value)


import re

tv = TestValue()
integer = re.compile(r"[-+]?\d+")
real = re.compile(r"[-+]?\d*\.\d+")
word = re.compile(r"\w+")

for inputValue in ("123 abc 3.1".split()):
if (tv << real.match(inputValue)):
print "Real", float(tv.value.group())
elif (tv << integer.match(inputValue)):
print "Integer", int(tv.value.group())
elif (tv << word.match(inputValue)):
print "Word", tv.value.group()

Prints:

Integer 123
Word abc
Real 3.1
 
P

Paul McGuire

This version is a bit better, since it follows the convention that
'<<' should return self.

class TestValue(object):
"""Class to support assignment and test in single operation"""
def __init__(self,v=None):
self.value = v

"""Add support for quasi-assignment syntax using '<<' in place of
'='."""
def __lshift__(self,other):
self.value = other
return self

def __bool__(self):
return bool(self.value)
__nonzero__ = __bool__

-- Paul
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top