Can I remove double evaluation whilst keeping lambda expression - python

def bar(x):
# some expensive calculation
<snip>
foo = lambda(x): bar(x) if bar(x) > 10 else 0
However here I have calculated foo twice. Is there a way to still write this as a one liner but avoid the double evaluation. I tried
foo = lambda(x): v if (v = bar(x)) > 10 else 0
but that doesn't work.

Preevaluate:
foo = lambda(x): x if x > 10 else 0
result = foo(bar(x))
Here you can see what is the similarities to your code:
lambda (x): foo(x) if foo(x) > 10 else 0 == (lambda(x): x if x > 10 else 0)(foo(x))
What you seek is not possible unless you create some kind of mutable state object or some other weird trick.
#Alakazam answer is tricky and smart, use it on your own risk. It can be better using iterators and next to avoid extra intermediate list:
lambda x: next(res if res > 10 else 0 for res in (bar(x), ))
Here you have the live example

Yes, you can avoid double evaluation in a lambda. But it's really ugly, and you should avoid it. Here's how it looks:
foo = lambda x: next(b if b > 10 else 0 for b in [bar(x)])
Is this easy to read and understand? No, absolutely not. I'm not going to explain it; see if you can figure it out. This clearly isn't a good solution, so what should you do instead? You should use a real function instead of a lambda.
def foo(x):
b = bar(x)
return b if b > 10 else 0
This is much easier to read and clearly better.

You may want to do this only if your function is very long to execute, else you shouldn't mind running it twice. You can't use list comprehension.
foo = lambda x: [res if res>10 else 0 for res in [bar(x)]][0]

Might as well just define another function:
def bar(x):
# some expensive calculation
<snip>
def bar_threshold(x,t):
y = bar(x)
return y if y>t else 0
foo = lambda x: bar_threshold(x,10)
(or redefine bar, if you find yourself using it only with the threshold)

I've tried by make some function decorator / wrapper...
def funcdec(func):
def inner(x):
if func(x) > 10:
return func(x)
else:
return 0
then
#funcdec
def bar(x):
return x * 2
then i try....:
foo = lambda x: bar(x)
give me result :
foo(2)
return 0
and
foo(10)
return 20

Related

modify recursive function without copy-paste python

I found that I want to modify a recursive function's behavior for a specific input. I know I can do this by rewriting the function, but as the function could be long I want to avoid duplicating code.
As an example, let's say I have implemented the function lambda x: max(x, 10) in the following recursive way:
def orig_fun(x):
if x < 10:
return orig_fun(x + 1)
return x
but now I want to return 20 whenever the input is 5, as in the following
def desired_fun(x):
if x == 5:
return 20
if x < 10:
return orig_fun(x + 1)
return x
which is the same as adding an if statement in the begging of orig_fun or writing a new function copying the body of orig_fun. I don't want to do this because the body must be many many lines. Of course, doing new_fun = lambda x: 20 if x == 5 else orig_fun(x) does not work because new_fun(3) would be 3 instead of 20.
Is there a way I can solve this in Python3?
note that this is a duplicate of Extend recursive (library) function without code duplication which has no satisfying answer (some user talked about "hacky ways" not presented)
You can use a another function to wrap your main function like that:
def orig_fun(x):
if x < 10:
return orig_fun(x + 1)
return x
def wrapper(x):
if x == 5:
return 20
return orig_fun(x)
>>> print(wrapper(8)) # output: 10
>>> print(wrapper(5)) # output: 20
>>> print(wrapper(12)) # output: 12
update
so you want to change (extend) logic in your recursive function without touching it, then let's make your recursive function non-recursive!
# store orig_fun in another location
main_fun = orig_fun
# re-define orig_fun so it will do one more
# step in every call
def orig_fun(x):
if x == 5:
return 20
return main_fun(x)
>>> orig_fun(2) # output: 20
>>> orig_fun(5) # output: 20
>>> orig_fun(7) # output: 10
>>> orig_fun(12) # output: 12
>>> orig_fun(35) # output: 35

Simple Python Issue with Iteration and Lambda

lst = [1, 2, 3]
i = 0
f = lambda x: x * lst[i]
i = 1
print(f(10))
f = lambda x: x * lst[i]
i = 2
print(f(10))
f = lambda x: x * lst[i]
Above is my Python code and I thought it would print out 10, 20, but it says 20, 30. I don't understand why f is modified by i regardless of the explicit assignment. I've got to make it print 10, 20 using an iteration(actually the code is a simplified form of the original one), so it seems that f = lambda x: x * 1 is not allowed.
I think you're expecting f = lambda x: x * lst[i] to store value of i, but it doesn't work that way. When a function is defined, it is just stored to be used later, it is not evaluated when it is defined. It is evaluated only when it is called.
So, when you call f(10) for the first time, you're passing value of x as 10 and the interpreter looks up for the value of i in memory, which is 1 during first function call and 2 during second function call. That's why you get 20 30 as output.
Feel free to ask any question if you still have doubts.
i is global variable. so when you call f it uses the current value of i
look at
f = lambda x: x * lst[i]
lst = [1, 2, 3]
for i in range(len(lst)):
print(f(10))
output
10
20
30
Note, not related to your question, but f = lambda x: x * lst[i] is against PEP8 recommendations:
Always use a def statement instead of an assignment statement that
binds a lambda expression directly to an identifier:
Correct: def f(x): return 2*x
Wrong: f = lambda x: 2*x
The first form means that the name of the resulting function object is
specifically 'f' instead of the generic ''. This is more
useful for tracebacks and string representations in general. The use
of the assignment statement eliminates the sole benefit a lambda
expression can offer over an explicit def statement (i.e. that it can
be embedded inside a larger expression)
Imagine lambda expression as a truly function, so you will get these code:
lst = [1, 2, 3]
i = 0
def f(x):
return x * lst[i]
i = 1
print(f(10)) # currently x=10 and i=1
def f(x):
return x * lst[i]
i = 2
print(f(10)) # currently x=10 and i=2
def f(x):
return x * lst[i]
I know what you mean. In your head, while you define lambda x: x * lst[i], you think number i will be frozen at this time --- just like assignment. When it be called later, the number i will always be the first value. It's not True. The value of i will be referenced when you call this function.

Pass a variable that increases as it is called?

How can I do this in python?
a = 0
func(a+=1) # a = 1
func(a+=1) # a = 2
Now I have had to solve it like this:
a = 0
a+=1
func(a)
a+=1
func(a)
...
and there must be a better way, right?
Edit:
Actually I also want to be able to pass it to different functions:
a = 0
a+=1
func1(a)
a+=1
func2(a)
a+=1
func1(a)
...
your solution is okay, but if you want to have a counting side effect, use itertools.count object:
import itertools
def f(x):
print(x)
c = itertools.count()
f(next(c))
f(next(c))
or the variant, performing the next call in the functions themselves (itertools.counter is mutable so you can modify it inside the function):
import itertools
def f(c):
x = next(c)
print(x)
c = itertools.count()
f(c)
f(c)
you can initialize it to a non-zero value: c = itertools.count(3)
Something simple like this:
a = 0
a+=1;func1(a)
a+=1;func2(a)
Each line is only 2 characters longer than your original request.
You can have a wrapping function that calls your function f and simultaneously increment the value of j!
>>> def f(a):print("Value of a is: %d"%a)
...
>>> c=lambda i:(i+1,f(i+1))
>>> j=0
>>> j,_=c(j)
Value of a is: 1
>>> j
1
>>> j,_=c(j)
Value of a is: 2
>>> j
2
There is no way in the sense that in Python, assignment is an instruction, not an operator whose operation returns a value.
You'll have to define a function and either use the global keyword with a or turn a into a mutable. You can also use a decorator for your functions.
a = [0]
#a = 0 # alternative version
def inc(x):
x[0] += 1
return x[0]
# global a # alternative version
# a += 1
# return a
def f1(x):
return x + 1
def f2(x):
return x + 2
# or (inspired by #jpp comment) decorate your functions
def inc1(x):
def inner(x):
x[0] += 1
return x[0]
return inner
#inc1
def f3(x):
return x
for i in range(10):
print(inc(a))
print()
print(f1(inc(a)))
print(f2(inc(a)))
print()
a = [0]
print(f3(a))
print(f3(a))

How to create dispatch style lambda function using Python?

If I have the given dispatch-style function to represent a pair, how can I implement the same using a one-line lambda function?
# ADT Level 0 (dispatch-style pair)
def make_pair(x, y):
"""Dispatch-style pair"""
def dispatch(m):
if m == 0:
return x
elif m == 1:
return y
return dispatch
You could do something like:
make_pair = lambda x,y: lambda m: x if m == 0 else y if m == 1 else None
The outer lambda returns an (inner) lambda waiting for an argument m that returns the bound variables in the scope created by the outer.
>>>one_two = make_pair(1, 2)
>>>one_two(1)
2
>>> one_two(2)
>>>
You can use imbricated lambdas to return a lambda expression:
>>> make_pair=lambda x,y:lambda m:x if m==0 else y
>>> a=make_pair(2,4)
>>> a(1)
4
>>> a(0)
2
lambda m:x if m==0 else y is (more or less) equivalent to your dispatch function (a(2) will return 4 in my case)

Best way to do conditional assignment in python

I tend to use this a lot, but it's ugly:
a = (lambda x: x if x else y)(get_something())
So I wrote this function:
def either(val, alt):
if val:
return val
else:
return alt
So you can do:
a = either(get_something(), y)
Is there a built-in function for this (similar to ISNULL in T-SQL)?
The or operator does what you want:
get_something() or y
In fact, it's chainable, like COALESCE (and unlike ISNULL). The following expression evaluates to the left-most argument that converts to True.
A or B or C
Easy!
For more conditional code:
a = b if b else val
For your code:
a = get_something() if get_something() else val
With that you can do complex conditions like this:
a = get_something() if get_something()/2!=0 else val
You may use:
a = get_something() or y
If get_something is True in boolean context, its value will be assigned to a. Otherwise - y will be assigned to a.
You can use a simple or, like so:
>>> a = None
>>> b = 1
>>> c = (a or b) # parentheses are optional
>>> c
1
I have provided an answer to this question to another user. Check it out here:
Answer to similar question
To respond quickly here, do:
x = true_value if condition else false_value
I'm also using the (a,b)[condition based on the value of a] form, saving the result of the get_something() call into a, in the rare cases that are best presented here: http://mail.python.org/pipermail/python-list/2002-September/785515.html
...
a=0 b=None a or b => None (a,b)[a is None] => 0
a=() b=None a or b => None (a,b)[a is None] => ()
...

Categories

Resources