Create a new function from a list of functions [duplicate] - python

This question already has answers here:
Apply a list of Python functions in order elegantly
(2 answers)
Closed 2 years ago.
Consider a few simple functions:
add2 = lambda x: x+2
add3 = lambda x: x+3
add4 = lambda x: x+4
And having them stored in a list:
funcs = [add2, add3, add4]
Is there a way, how to create a new function, which applies all the given ones?
Not working solution:
f = funcs[0]
for g in funcs[1:]:
f = lambda x: g(f(x))
This does not work, since after trying to call the create function f(0), I get RecursionError: maximum recursion depth exceeded, which I don't completely understand.
The solution for the question Apply a list of Python functions in order elegantly does not work for my problem.
I don't want to get to the result (yet), I want to construct a new function
from functools import reduce
result = reduce(lambda res, f: f(res), funcs, val)
However, it should work with a combination of partial.

Working solution with functools:
import functools
f = functools.partial(functools.reduce, lambda res, f: f(res), funcs)
Working solution (without lambdas):
def _inner(x):
for f in funcs:
x = f(x)
return x
Calling _inner(0) returns correctly 9.

Related

Python: calc n factorial only use call expressions, conditional expressions, and lambda expressions

This is an interesting question from online.
The full question is:
To write a recursive function, we have always given it a name using a def or assignment statement so that we can refer to the function within its own body. In this question, your job is to define it recursively without giving it a name!
Write an expression to complete the function make_anonymous_factorial(),which computes n factorial using only call expressions, conditional expressions, and lambda expressions (no assignment or def statements). Note in particular that you are not allowed to use make_anonymous_factorial in your return expression. The sub and mul functions from the operator module are the only built-in functions required to solve this problem.
e.g.
>>> make_anonymous_factorial( )(5)
120
Here is my solution:
from operator import sub, mul
def make_anonymous_factorial():
from functools import reduce
return lambda n:reduce(mul, range(1, n + 1))
However, as the question described,The sub and mul functions from the operator module are the only built-in functions required to solve this problem, since I used reduce( ), I don't think it is a suitable answer.
Is there a better solution?
(The question is from cs61a summer 2020 HW03, Q6, and here is the link. It's the last question which is on the bottom of the page.)
After reading the article Frank mentioned up to the point where it talks about a function getting itself as argument, I tried that (Try it online!):
from operator import sub, mul
def make_anonymous_factorial():
return (lambda f: lambda n: f(n, f))(
lambda n, f: mul(n, f(sub(n, 1), f)) if n else 1
)
print(make_anonymous_factorial()(5))
The innermost lambda n, f: is the real factorial computer, and it'll get itself as second argument. That is organized by the outer two lambdas. The lambda n: is the one I return, it calls the real factorial with n and itself.
Here is a good explanation of the Y combinator. Its example is writing factorial in Python!
https://lptk.github.io/programming/2019/10/15/simple-essence-y-combinator.html
If lambda is OK, this code works:
f = lambda x: x * f(x - 1) if x > 1 else 1
# example
print(f(5)) # 120
Without assignment using reduce from functools:
from functools import reduce
print(reduce(lambda x, y: x * y, list(range(1, 5 + 1)))) # 120

How do I append a lambda to a list in python? [duplicate]

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
I am trying to make a program that creates a list of lambda functions of the format y=mx+b, where 'm' and 'b' are predetermined values
My overall goal is to implement a function that
Takes a picture
Finds the lines on it
Extends them across the whole picture in a solid colour
Basically, something like a Hough transforms if you know what that is.
Once I have the lines for a specific image, I can create a lambda function to represent the slope of the line and where it begins. I'm having an issue not being able to append a lambda function to the list.
I have tried this :
if __name__ == "__main__":
nums = []
for i in range(10):
j = lambda x: x + i
nums.append(j)
for i in nums:
print(i(1))
Here is the error I'm getting :
Traceback (most recent call last):
File "C:/Users/me/.PyCharmCE2018.3/config/scratches/scratch_3.py", line 7, in <module>
print(i(1))
File "C:/Users/me/.PyCharmCE2018.3/config/scratches/scratch_3.py", line 4, in <lambda>
j = (lambda x: x + i)
TypeError: unsupported operand type(s) for +: 'int' and 'function'
The problem is that the lambdas you create are referring to the current value of i in the active stack frame. When you later reuse i for the second for loop, it is bound to the lambdas in your list. When invoked as i(1), the lambdas are trying to evaluate 1 + i where i is the lambda, so of course you get an error.
Probably what you want is to freeze the value of i at the point at which the lambda is created. You can do this by replacing:
j = lambda x: x + i
with:
j = (lambda y: lambda x: x + y)(i)
This effectively captures the current value of i by binding it to a lambda variable, then immediately applying that lambda, after which the binding remains fixed.
This will give you a clue:
>>> i=1
>>> a=lambda x:x+i
>>> a(5)
6
>>> i=2
>>> a(5)
7
lambda uses i in the outer scope. In the OP case, all the functions are the same. Using i in the final loop makes i a function, not an integer. Change it to something else, and you'll find the functions are all the same, using the last value of i:
nums = []
for i in range(10):
j = lambda x: x + i
nums.append(j)
for f in nums:
print(f(1))
10
10
10
10
10
10
10
10
10
10
The fix is, make i a parameter to the function, to capture the value as a local variable:
nums = []
for i in range(10):
j = lambda x,i=i: x + i
nums.append(j)
for f in nums:
print(f(1))
1
2
3
4
5
6
7
8
9
10
Your value of i has changed and it's not what you think.
First you create lambda:
j = lambda x: x + i
in hope, that i will remain as CURRENT value (so 0, 1, 2 and so on).
Then you execute it:
print(i(1))
Do you see, how you named your second iterator variable i? Change it to j and your example will work. Why? Because python resolves value of i in your lambda, when you execute it, not when you define it. So when you execute your lambda (i(1)) it will go to your lambda body and try x + i. Then it will lookup i, which now contains your lambda (not the INTEGER!). Hence your problem.
You need to do double function to make it work properly. Try this:
if __name__ == "__main__":
nums = []
for i in range(10):
def generate_lambda(i):
return lambda x: x + i
j = generate_lambda(i)
nums.append(j)
for i in nums:
print(i(1))
Why does this work? When you call generate_lambda, there will be i variable with your INTEGER value. It will shadow variable i used later on to iterate over lambdas. And since you never modify i variable inside generate_lambda function, it will stay like this forever.
I think you need to learn something more about lambda functions...
Actually, it's syntax is like : [lambda arguments: expression]
So, the issue is you have two variables in the expression, so you need to pass two arguments.
I don't really get what you want to achieve by this function, but I guess you need to have two arguments for m and b.
In your code, you need to initialize x and pass it as an argument to lambda.
nums = []
x=0
for i in range(10):
j = lambda x,i : x + i
nums.append(j)
for i in nums:
print(i(1,1))
You can use operator.add and functools.partial and do not lambda at all:
import operator
import functools
if __name__ == "__main__":
nums = []
for i in range(10):
nums.append(functools.partial(operator.add, i))
for i in nums:
print(i(1))

Defining Anonymous functions by list Comprehension [duplicate]

This question already has answers here:
Local variables in nested functions
(4 answers)
Closed 4 years ago.
I am in need of creating functions (a lot) and storing inside an array or list. I tried using list comprehensions for generating functions (like the code shown below, indeed a simple case).
f = [lambda x: x*i for i in range(0,3)]
which gives
f[0](1) = 2 # expected 0
f[1](1) = 2 # expected 1
f[2](1) = 2 # expected 2 (no prblm with last case)
But instead of using iterators (like list comprehensions) to generate functions, if I write functions explicitly inside a list(defining each function), it works fine.
So, is there anything wrong with the above code(which uses iterators to generate anonymous functions)?
I believe this variant of the syntax will give you what you want:
f = [lambda x, i=n: x * i for n in range(0, 3)]
EXAMPLES
>>> f[0](1)
0
>>> f[1](1)
1
>>> f[2](1)
2
>>>
I believe what #user2357112 is leading you towards is the variation:
from functools import partial
f = [partial(lambda x, i: x * i, i=n) for n in range(0, 3)]
which may not be easy to tease out of the cited duplication page.
The inside of your lambda function is evaluated when you call the function, not when you create the function. At this point point the value of i is 2. You can verify this by running:
>>> f = [lambda x: x*i for i in range(0,3)]
>>> i
2
As cdlane pointed out in his answer, you can fix this by storing the values from the range() statement into a default parameter on your lambda function:
>>> f = [lambda x, i=i: x*i for i in range(0,3)]
>>> f[0](1)
0
>>> f[1](1)
1
>>> f[2](1)
2
This works because unlike the function body, the function definition is evaluated when you create the function.

Order should be as specified! error [duplicate]

This question already has answers here:
What's the best way to return multiple values from a function? [duplicate]
(6 answers)
Closed 6 years ago.
def compose(f,g):
return lambda f: f + 1
return lambda g: g
how can I specify the order of the return statements
These are the test cases;
add1 = lambda a: a+1
this = lambda a: a
test.expect( compose(add1,this)(0) == 1 )
def compose(f1, g1):
# do something
return lambda f:f+1, lambda g:g
will return a tuple of two functions.
You can get the individual functions like this:
func1, func2 = compose(a,b)
You cannot have two return statements in a function. Once the first one is called, the second will not be reached because the function has already returned. You could, however, use a tuple to organize the output, which would look like this.
def compose(f,g):
return (lambda f: f + 1, lambda g: g)
Be careful though, because this will return the actual lambdas as the below example shows:
In [7]: def func(f, g):
...: return (lambda f: f + 1, lambda g: g)
...:
In [8]: func(0, 0)
Out[8]: (<function __main__.<lambda>>, <function __main__.<lambda>>)
Notice the types shows by line out[8]. This means that what ever variables that the function returns to will be the actual functions, not a number. To return a number, don't use lambdas, just calculate the numbers normally.
It's also worth noting, that the parameters have no effect on this function.
def compose(f,g):
return lambda f: f + 1,lambda g: g
print compose(f,g)[0]
print compose(f,g)[1]

Sequential function mapping in python

I have a bunch of functions in a list:
funcs = [f1, f2, f3, f4, f5]
and all of the functions take in return a single argument, eg.
f1 = lambda x: x*2
I'd like to map all these functions together
result = lambda x: f5(f4(f3(f2(f1(x)))))
or, iterating over funcs
def dispatch(x):
for f in funcs:
x = f(x)
return x
dispatch works fine, but I couldn't figure out a clean way to do this using iterools. Is it possible? Does this sequential function mapping idiom have a name?
There is no point in using itertools here; you are producing one output, and you could not apply this to an infinite iterable. You have to have a finite number of functions in the input iterable for this to work at all.
Use the reduce() function:
from functools import reduce
x = reduce(lambda res, func: func(res), funcs, x)
The functools.reduce() import helps the above work in both Python 2 and 3.
reduce(), together with map(), filter() and, yes, itertools, is an often used tool in functional programming.
Another (less efficient, alas) way of looking at Martijn's answer is to realize that you want to compose the list of functions.
# function composition: compose(f,g)(x) = f(g(x))
def compose(f, g):
return lambda x: f(g(x))
# Identity for function composition
# compose(f, identity)(x) = f(x)
identity = lambda x: x
# result(x) = f1(f2(...fn(x)...))
result = reduce(compose, funcs, identity)

Categories