Conditional statement in a one line lambda function in python? [duplicate]
Asked Answered
A

8

81

Apologies if this has been asked before, but I couldn't see it anywhere.

Essentially I've come across a scenario where i need to make use of an if statement inside a lambda function. What makes it difficult is that ideally it needs to be in a single line of code (if thats even possible?)

Normally, i would write this:

T = 250

if (T > 200):
    rate = 200*exp(-T)
else:
    rate = 400*exp(-T)

return (rate)

However i need it to look like this:

rate = lambda(T) : if (T>200): return(200*exp(-T)); else: return(400*exp(-T))

I realize the easier thing to do would to take the decision making outside of the lambda functions, and then have a separate lambda function for each case, but its not really suitable here. The lambda functions are stored in an array and accessed when needed, with each array element corresponding to a particular "rate" so having two separate rows for the same "rate" would mess things up. Any help would be greatly appreciated, or if its not possible, some confirmation from others would be nice :)

Adhamh answered 2/4, 2013 at 19:25 Comment(5)
I doubt-squared that you need a one-line lambda function, because I doubt that you need a one-line function, and I doubt that you need a lambda function as opposed to a named function. What's the point of using a lambda if you're immediately going to give your function the name rate anyhow?Chronology
Too bad I can only +1 DSM once… But to make it clear: the easier thing to do is not to "take the decision making outside of the lambda functions", but to just define them as regular functions in the first place. You can store regular functions in an array. There's nothing special about lambdas; they're more limited functions, not more powerful functions.Cooperman
Well the function needed to fit in one line, which i didn't think you could do with a named function? Also these functions are stored as strings which are then evaluated using "eval" which i wasn't sure how to do with regular functions.Adhamh
First, why does it need to fit in one line? Second, why are they stored as strings and then evaluated using eval? Those are both very bad requirements. I suspect there's an XY problem here, and if you told us what you were actually trying to do, we could explain the right way to do it.Cooperman
@NathanBush can u mark as accepted any of the answer which worked for you? or neither of these worked?Judicatory
D
118

Use the exp1 if cond else exp2 syntax.

rate = lambda T: 200*exp(-T) if T>200 else 400*exp(-T)

Note you don't use return in lambda expressions.

Duley answered 2/4, 2013 at 19:27 Comment(0)
C
27

The right way to do this is simple:

def rate(T):
    if (T > 200):
        return 200*exp(-T)
    else:
        return 400*exp(-T)

There is absolutely no advantage to using lambda here. The only thing lambda is good for is allowing you to create anonymous functions and use them in an expression (as opposed to a statement). If you immediately assign the lambda to a variable, it's no longer anonymous, and it's used in a statement, so you're just making your code less readable for no reason.

The rate function defined this way can be stored in an array, passed around, called, etc. in exactly the same way a lambda function could. It'll be exactly the same (except a bit easier to debug, introspect, etc.).


From a comment:

Well the function needed to fit in one line, which i didn't think you could do with a named function?

I can't imagine any good reason why the function would ever need to fit in one line. But sure, you can do that with a named function. Try this in your interpreter:

>>> def foo(x): return x + 1

Also these functions are stored as strings which are then evaluated using "eval" which i wasn't sure how to do with regular functions.

Again, while it's hard to be 100% sure without any clue as to why why you're doing this, I'm at least 99% sure that you have no reason or a bad reason for this. Almost any time you think you want to pass Python functions around as strings and call eval so you can use them, you actually just want to pass Python functions around as functions and use them as functions.

But on the off chance that this really is what you need here: Just use exec instead of eval.

You didn't mention which version of Python you're using. In 3.x, the exec function has the exact same signature as the eval function:

exec(my_function_string, my_globals, my_locals)

In 2.7, exec is a statement, not a function—but you can still write it in the same syntax as in 3.x (as long as you don't try to assign the return value to anything) and it works.

In earlier 2.x (before 2.6, I think?) you have to do it like this instead:

exec my_function_string in my_globals, my_locals
Cooperman answered 2/4, 2013 at 19:45 Comment(0)
S
11

Yes, you can use the shorthand syntax for if statements.

rate = lambda(t): (200 * exp(-t)) if t > 200 else (400 * exp(-t))

Note that you don't use explicit return statements inlambdas either.

Salve answered 2/4, 2013 at 19:28 Comment(3)
Further shortening: rate = lambda(t): (200 if t > 200 else 400) * exp(-t)Minnow
@Minnow Quite true, though arguably less explicit in illustrating the answer to the question.Salve
The parens after "lambda" are also superfluous.Walley
G
6

I found I COULD use "if-then" statements in a lambda. For instance:

eval_op = {
    '|'  : lambda x,y: eval(y) if (eval(x)==0) else eval(x),
    '&'  : lambda x,y: 0 if (eval(x)==0) else eval(y),
    '<'  : lambda x,y: 1 if (eval(x)<eval(y)) else 0,
    '>'  : lambda x,y: 1 if (eval(x)>eval(y)) else 0,
}
Greenstone answered 5/10, 2013 at 23:32 Comment(0)
I
5

By the time you say rate = lambda whatever... you've defeated the point of lambda and should just define a function. But, if you want a lambda, you can use 'and' and 'or'

lambda(T): (T>200) and (200*exp(-T)) or (400*exp(-T))
Iliac answered 2/4, 2013 at 19:46 Comment(0)
B
4

In case you want to be lazier:

#syntax lambda x : (false,true)[Condition]

In your case:

rate = lambda(T) : (400*exp(-T),200*exp(-T))[T>200]
Baelbeer answered 12/6, 2020 at 4:31 Comment(0)
W
0

Gaba's method that using tuple slices has side effect: both of condition in tuple would be evaluated first, then the expression in bracket is evaluated as an arbitrary value, which False selects former and True selects the latter.

As self-called function (recursion) mostly need tail recursive condition evaluated first, this method that evaluate first then select may cause infinity recursion and raises RecursionError as a result.

>>> b = lambda x: (x,x*b(x-1))[x>1]
>>> print(b(3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
  File "<stdin>", line 1, in <lambda>
  File "<stdin>", line 1, in <lambda>
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded
>>> b = lambda x: x*b(x-1) if x>1 else x
>>> print(b(3))
6

And for the question itself (Y problem), see Does Python have a ternary conditional operator?

Wilkins answered 28/1, 2023 at 16:46 Comment(0)
S
0

All of this looks like over engineering to me.

rate = (200 if T > 250 else 400) * exp(-T)

looks way easier to read IMHO.

Suspensory answered 2/7, 2023 at 23:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.