Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > if/elif chain with assignment expressions

Reply
Thread Tools

if/elif chain with assignment expressions

 
 
Larry Bates
Guest
Posts: n/a
 
      07-12-2004
What about:

e_list=[{'condition': 'f(y) < 5', 'call': fred},
{'condition': 'f(y) < 7', 'call': ted},
{'condition': 'f(y) < 9', 'call': ned}]

for e in e_list:
if eval(e['condition']):
e['call'](y)
break

Its easily extendable and would support an unlimited
number of function calls and conditions by merely
extending e_list definition. It also already works
with current implementation of Python.

HTH,
Larry Bates
Syscon, Inc.


"Paul Rubin" <http://(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Sometimes you want to compute an expression, then do something with
> the value if it meets a certain criterion; otherwise, try a different
> expression (and maybe different criterion) instead, etc. With := as
> an assignment expression operator, you could write:
>
> if (y := f(x)) < 5:
> fred(y)
> elif (y := g(x)) < 7:
> ted(y)
> elif (y := h(x)) < 9:
> ned(y)
> etc.
>
> Of course there are alternative ways of doing the same thing, but they
> all seem to be messier.



 
Reply With Quote
 
 
 
 
Duncan Booth
Guest
Posts: n/a
 
      07-12-2004
"Larry Bates" <(E-Mail Removed)> wrote in news:RPudnSx-4L-GOW_dRVn-
http://www.velocityreviews.com/forums/(E-Mail Removed):
> "Paul Rubin" <http://(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> Sometimes you want to compute an expression, then do something with
>> the value if it meets a certain criterion; otherwise, try a different
>> expression (and maybe different criterion) instead, etc.

> What about:
>
> e_list=[{'condition': 'f(y) < 5', 'call': fred},
> {'condition': 'f(y) < 7', 'call': ted},
> {'condition': 'f(y) < 9', 'call': ned}]
>
> for e in e_list:
> if eval(e['condition']):
> e['call'](y)
> break


(I've moved the response to after the original text so that people can
follow the thread)

It isn't generally a good idea to use eval when there are better options
around. Your suggestion could equally well be written without the eval:
(Changed back to f, g, h as per original post)

e_list=[{'condition': lambda: f(y) < 5, 'call': fred},
{'condition': lambda: g(y) < 7, 'call': ted},
{'condition': lambda: h(y) < 9, 'call': ned}]

for e in e_list:
if e['condition']():
e['call'](y)
break

Whilst I see your reason for using a dictionary, I would tend more towards
a tuple for code like this:

def doit(y):
e_list=[ (lambda: f(y) < 5, fred),
(lambda: g(y) < 7, ted),
(lambda: h(y) < 9, ned)]
for (condition,action) in e_list:
if condition():
action(y)
break

If the program contains multiple bits of code like this, you could
naturally extract the for loop out into another function, whereupon this
becomes:

def doit(y):
do_first_true((lambda: f(y) < 5, fred),
(lambda: g(y) < 7, ted),
(lambda: h(y) < 9, ned))

def do_first_true(*branches):
for (condition,action) in branches:
if condition():
action(y)
break

which is definitely less messy than assignments in conditionals and allows
for variations on the theme such as do_all_true.
 
Reply With Quote
 
 
 
 
Paul Rubin
Guest
Posts: n/a
 
      07-12-2004
"Larry Bates" <(E-Mail Removed)> writes:
> What about:
>
> e_list=[{'condition': 'f(y) < 5', 'call': fred},
> {'condition': 'f(y) < 7', 'call': ted},
> {'condition': 'f(y) < 9', 'call': ned}]
>
> for e in e_list:
> if eval(e['condition']):
> e['call'](y)
> break
>
> Its easily extendable and would support an unlimited number of
> function calls and conditions by merely extending e_list definition.
> It also already works with current implementation of Python.


It throws away the value from evaluating the condition. Also, it uses
eval a lot, which adds a lot of overhead. You wanted something like:

e_list = [{'expr': lambda: f(x), 'condition': lambda y: y<5,
'call': lambda y: fred(y)},
{'expr': lambda: g(x), 'condition': lambda y: y<7,
'call': lambda y: ted(y)},
{'expr': lambda: h(x), 'condition': lambda y: y<9,
'call': lambda y: ned(y)}]
for e in e_list:
y = e.expr()
if e.cond(y):
e.call(y)
break

which is an unbelievably contorted way of replacing a straightforward
if/elif chain. And of course that wants an assignment expression too:

for e in e_list:
if e.cond(y := e.expr()):
e.call(y)
break
 
Reply With Quote
 
Paul Rubin
Guest
Posts: n/a
 
      07-12-2004
Paul Rubin <http://(E-Mail Removed)> writes:
> e_list = [{'expr': lambda: f(x), 'condition': lambda y: y<5,
> 'call': lambda y: fred(y)},
> {'expr': lambda: g(x), 'condition': lambda y: y<7,
> 'call': lambda y: ted(y)},
> {'expr': lambda: h(x), 'condition': lambda y: y<9,
> 'call': lambda y: ned(y)}]
> for e in e_list:
> y = e.expr()


Bah, I forgot you can't even say e.expr(), you have to say e['expr']().
(I've been doing too much Javascript).
 
Reply With Quote
 
Peter Abel
Guest
Posts: n/a
 
      07-12-2004
Paul Rubin <http://(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> Sometimes you want to compute an expression, then do something with
> the value if it meets a certain criterion; otherwise, try a different
> expression (and maybe different criterion) instead, etc. With := as
> an assignment expression operator, you could write:
>
> if (y := f(x)) < 5:
> fred(y)
> elif (y := g(x)) < 7:
> ted(y)
> elif (y := h(x)) < 9:
> ned(y)
> etc.
>
> Of course there are alternative ways of doing the same thing, but they
> all seem to be messier.


When I started learning C, I remember there were big efforts to
be done to comprehend that an assignment returns a value that could
be used for a boolean decision. Once I had understood it I was glad
to have it. But always there was a little pitfall cause an assignment
and a comparison of equality were legal C-code. And the compiler did
what I wrote and not alway what I wanted it to do. So Python forces
me to say excactly what to do and there are solutions for any case.
Let me change your lines to the followings:

> if (assign('y',f(x)) < 5:
> fred(y)
> elif (assign('y',g(x)) < 7:
> ted(y)
> elif (assign('y',h(x)) < 9:
> ned(y)


And I think this code is clear enough to be readable and
self-documenting. Python gives us the utils to do so as the
following snippet shows:

>>> def assign(symbol,value):

.... globals()[symbol]=value
.... return value
....
>>> x=2
>>> f=lambda val:val*val
>>> if assign('y',f(x))<5:

.... print 'y<5; y=',y
.... else:
.... print 'y>=5; y=',y
....
y<5; y= 4
>>> if assign('y',f(4))<5:

.... print 'y<5; y=',y
.... else:
.... print 'y>=5; y=',y
....
y>=5; y= 16
>>>


Hope it helps a bit.

Regards
Peter
 
Reply With Quote
 
Paul Rubin
Guest
Posts: n/a
 
      07-12-2004
(E-Mail Removed) (Peter Abel) writes:
> But always there was a little pitfall cause an assignment
> and a comparison of equality were legal C-code. And the compiler did
> what I wrote and not alway what I wanted it to do.


I have never for the life of me comprehended why so many people think
that's a problem. Yes, you can confuse '=' with '==', but you can also
confuse '<' with '<=', or '<' with '>'. Anyway, the usual solution
is to make the assignment-expression operator something like ':='
(the standard assignment operator in Algol) so that '=' in an expression
remains invalid. That seems to make the '='/'==' confusion go away.

> Let me change your lines to the followings:
>
> > if (assign('y',f(x)) < 5:
> > fred(y)
> >>> def assign(symbol,value):

> ... globals()[symbol]=value
> ... return value


Yuch, now you're going to make a GLOBAL variable to hold that saved
value? You're surely better off using a class instance or closure.
But either way is a mess compared to just using a local variable in
the natural way.
 
Reply With Quote
 
David Fraser
Guest
Posts: n/a
 
      07-13-2004
John Roth wrote:
> "Paul Rubin" <http://(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>
>>steve holden <(E-Mail Removed)> writes:
>>
>>>Indeed, you might think so. But this topic has been discussed
>>>exhaustively (which isn't to say you aren't about to hear a lot more
>>>about the subject) in this group, and the assignment operation is
>>>*not* an operator for specific reasons the FAQ attempts to make clear
>>>in
>>>

>
> http://www.python.org/doc/faq/genera...-an-expression
>
>>Yeah, I've seen those discussions before. The if/elif/elif example was
>>something I hadn't seen in those discussions, and it came up in some
>>code I was writing yesterday, so I posted about it.

>
>
> I thoroughly agree. I've come up with that any number
> of times, and allowing an assignment in an expression
> is one of the things that I think should be done.
>
> Note that I don't really care about the syntax, and
> I care even less if it's really intuitive to novices. It's
> one of those things that leads to simpler, more expressive
> code when you need it, but it's not something that's
> absolutely necessary to hack together a working
> program while you're learning the language.
>
> The use case is an expression in an if statement, not
> an expression in a while statement. The latter can
> be handled with an iterator and a for statement,
> which might be a good idea, and it might not depending
> on the specific situation.
>
> There is an alternative, which is to find all of the
> cases where this is likely to be a problem, and fix
> the calls so that they naturally return an iterator.
>
> To make this specific, let's take a look at the
> <string>.find and <string>.rfind. This method
> pair is probably the poster child of how not to
> do it in a pythonic manner.
>
> Let's assume we had a <string>.findall()
> method, defined to return a list of all
> indexes of the first character of each
> substring that matches the given string.
>
> Then we could say something like:
>
> for firstMatch in myString.findall("fubar")[:1]:
> do something with it
>
> While this is not exactly obvious to the novice,
> it not only gets the job done, but the findall()
> method also has a number of other very
> nice properties. It behaves properly in a boolean
> context, and it never returns an incorrect index
> (that is, -1.)
>
> If you really did want to process all matches,
> it's even easier.


I support str.findall ! Yes! Please!

David
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Assignment operator self-assignment check Chris C++ 34 09-26-2006 04:26 AM
Augument assignment versus regular assignment nagy Python 36 07-20-2006 07:24 PM
Volatiles in assignment expressions Daniel W C Programming 13 03-09-2006 06:35 AM
Delay chain Patrick VHDL 1 12-21-2004 03:20 PM
Add custom regular expressions to the validation list of available expressions Jay Douglas ASP .Net 0 08-15-2003 10:19 PM



Advertisments