This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 years ago.
I want to create a list that contains the monomials up to degree n
basis = [lambda x:x**i for i in range(0,n+1)]
This however creates a list of n functions, but all the same one (of degree n) and not of degree 0,1,2,...n
I tried without list comprehension as well:
basis = []
for i in range(0,n+1):
basis.append(lambda x:x**i)
but with the same result. Substituting the lambda function by a classic function definition also did not fix it.
I checked Python lambdas and scoping, but that did not help, since I don't want to store function values, but the function itself. For example, I want to be able to call
basis[0](34)
and this should return
1
As i said in the comments, take a look at partial
def f(x, n):
return x**n
basis = [partial(f, n=i) for i in range(10)]
print(basis[0](34)) # 1
This entry sums it up perfectly
http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures :
... you can create a closure that binds immediately to its arguments by using a default arg like so:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
You code would become:
basis = [lambda x,i=i:x**i for i in range(0,n+1)]
This is a bit of a hacky solution, but works. I still highly recommend to read the link provided as the 3 points that are made there are usual errors when you are new to Python.
Related
This question already has answers here:
How to map a list of data to a list of functions?
(5 answers)
Closed 2 years ago.
I have a function that creates a new array in which each item is a result of a function f(x) from a list of functions.
For example,
x= [1,2,3]
interFunctions = [f1,f2,f3]
and I want the result to be y = [f1(x[0]),f2(x[1]),f3(x[2])]
The first function is working fine, however, I wanted to use list comprehension to do this process, so that my code is not so slow. With my basics skills I tried to used my second function, it returns only one item and I can't get my head around how this list comprehension work for more than one list, can anyone explain to me?
First Function
def makeNewYaxisLstofArrays(newXaxisListofArray,lstInterFuncs):
for f in lstInterFuncs:
data = []
for x in newXaxisListofArray:
data.append(f(x))
return data
Tried using List Comprehension
def makeNewYaxisLstofArrays(newXaxisListofArray,lstInterFuncs):
for f in lstInterFuncs:
data = [f(x)for x in newXaxisListofArray]
for x in newXaxisListofArray:
return data
I think you've made a typo in your code, but I guess you wanted to write:
def makeNewYaxisLstofArrays(newXaxisListofArray,lstInterFuncs):
for f in lstInterFuncs:
data = [f(x) for x in newXaxisListofArray]
# for x in newXaxisListofArray: <- I guess it shouldn't be here
return data
The problem with your code is that you're creating data for each function. Your code takes the first function from lstInterFuncs and applies it to each element from newXaxisListofArray. This way in the first run of the loop (for the first element from lstInterFuncs) you get [f1(x1), f1(x2),...]. Then, you create the list for f2: [f2(x1), f2(x2),...], etc. Please note, that each time you overwrite the data variable. In the end, your function returns a list for the last function: [f3(x1), f3(x2), ...] (given you have 3 functions)
I think you should iterate over both at the same time. In my opinion, you may want to use a zip() function -> it can iterate over two lists (or more) at the same time and pack them into a tuple:
def makeNewYaxisLstofArrays(newXaxisListofArray,lstInterFuncs):
data = [f(x) for f, x in zip(lstInterFuncs, newXaxisListofArray)]
return data
The code will iterate over functions and values simultaneously, so you'll get [f1(x1), f2(x2), ...]
Use zip
x= [1,2,3]
interFunctions = [f1,f2,f3]
y = [f(arg) for f, arg in zip(interFunctions, x)]
This question already has answers here:
Modifying a list inside a function
(4 answers)
Closed 2 years ago.
I am currently new to python and I'm still learning the basics, but there is one thing I just can't wrap my head around. Why is the code in Q.1 giving the out-print 3, while Q.2 is giving the out-print [4]?
When asked, I was told that the f(x)-line at the bottom of Q.1 isn't given any variable or box to hold the new return-value given from the def. and that's the reason why the out-print of x remain 3.
This made sense to me, but then why would the out-print in Q.2 equal the return-value of g(x)? There isn't any variable or box to contain the return-value of x in this code either..
Q.1:
def f(x):
x += 1
return x
x=3
f(x)
print(x)
Q.2:
def g(x):
x[0] = x[0] + 1
return x
x = [3]
g(x)
print(x)
A Python function takes arguments by reference (something that points to the real object) whenever that argument is "complex", and takes the argument by value (a copy of the item) when it's a simple thing.
Q.1 is taking an int as an argument, then the function creates an internal copy of it and thus does not modify the value of x outside the function.
Q.2 is taking a list as an argument, which is considered complex, in which case the function takes a reference to the original and whatever happens to that reference will also happen to the original.
You can find an explanation of pass-by-reference and pass-by-value with images here
In Python, lists are mutable objects, and as a result they are passed-by-reference when used in a function call. This means that when g(x) adds 1 to the first element of x, after the function exits, the original list x will contain those changes.
Note that the specific term used is not "pass-by-reference", but rather "pass-by-name", which comes with a couple different semantics, which you can learn more about if you wish.
The function defined is Q1 is returning a value of for. x contains 3 and is passed into the function, by calling it with f(x). It gets incremented and returned to the function call. But, the function call was not stored in a variable, so it was not saved into memory. Nothing was done with the returned value. Calling the function is only editing the variable x within the local scope (within the function). When you're using print(x) it is referencing the global variable of x, which still contains 3.
In Q2, lists are mutable. Editing them within a function, the changes persist in the global scope. Because that list is mutated in the global scope, using print(x) uses the updated global variable.
I hope this makes sense. Look into scope of variables in the documentation for more.
Q1
def f(x):
x += 1
return x
x=3
f(x)
print(x)
The reason this is returning 3 and not 4 is because you haven't rebound your variable to reference this new value. Instead of f(x) you can do x = f(x).
Q2
def g(var):
var[0] = var[0] + 1
return var
x = [3]
g(x)
print(x)
To answer this without making it confusing I've changed the local variable used in the function to var so you can see what I'm trying to explain to you easier.
First you are creating a list with a integer value 3 in the first spot in the list (element 0) and you make x reference this list.
When you call g() function and pass the list, the function sets var to reference the same list (not a different one, the same one). You then tell the function to increase the integer value in the first element by 1. Since lists are mutable with certain methods, you have already changed the list for both the local variable var, and the global variable x. This means that you actually don't need to use any return of the function because the list has been mutated in place.
Have a look at this video https://youtu.be/_AEJHKGk9ns where Ned Batchelder explains more about this.
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 3 years ago.
I have a vector with some parameters and I would like to create a dictionary of anonymous (lambda) functions in Python3.
The goal of this is to create a callable function that gives values equal to the sum of these functions with the same argument.
I am struggling even to create a dictionary with the original lambda function objects and get them to behave consistently. I use the following code:
import numpy as np
a = np.linspace(0,2.0,10)
func = {}
for i,val in enumerate(a):
print(i)
func['f{}'.format(i)] = lambda x: x**val
print(func['f0'](0.5))
print(func['f1'](0.5))
print(func['f2'](0.5))
print(func['f3'](0.5))
The output of the final print statements gives the same value, whereas I would like it to give the values corresponding to x**val with the value of val coming from the originally constructed array a.
I guess what's happening is that the lambda functions always reference the "current" value of val, which, after the loop is executed is always the last value in the array? This makes sense because the output is:
0
1
2
3
4
5
6
7
8
9
0.25
0.25
0.25
0.25
The output makes sense because it is the result of 0.5**2.0 and the exponent is the last value that val takes on in the loop.
I don't really understand this because I would have thought val would go out of scope after the loop is run, but I'm assuming this is part of the "magic" of lambda functions in that they will keep variables that they need to compute the function in scope for longer.
I guess what I need to do is to insert the "literal" value of val at that point into the lambda function, but I've never done that and don't know how.
I would like to know how to properly insert the literal value of val into the lambda functions constructed at each iteration of the loop. I would also like to know if there is a better way to accomplish what I need to.
EDIT: it has been suggested that this question is a duplicate. I think it is a duplicate of the list comprehension post because the best answer is virtually identical and lambda functions are used.
I think it is not a duplicate of the lexical closures post, although I think it is important that this post was mentioned. That post gives a deeper understanding of the underlying causes for this behavior but the original question specifically states "mindful avoidance of lambda functions," which makes it a bit different. I'm not sure what the purpose of that mindful avoidance is, but the post did teach related lessons on scoping.
The problem with this approach is that val used inside your lambda function is the live variable, outside. When each lambda is called, the value used for val in the formula is the current value of val, therefore all your results are the same.
The solution is to "freeze" the value for val when creating each lambda function - the way that is easier to understand what is going on is to have an outer lambda function, that will take val as an input, and return your desided (inner) lambda - but with val frozen in a different scope. Note that the outer function is called and imedially discarded - its return value is the original function you had:
for i,val in enumerate(a):
print(i)
func[f'f{i}'] = (lambda val: (lambda x: x**val))(val)
shorter version
Now, due to the way Python stores default arguments to functions, it is possible to store the "current val value" as a default argument in the lambda, and avoid the need for an outer function. But that spoils the lambda signature, and the "why" that value is there is harder to understand -
for i,val in enumerate(a):
print(i)
func[f'f{i}'] = lambda x, val=val: x**val
This question already has answers here:
How exactly does a generator comprehension work?
(8 answers)
Closed 3 months ago.
I was using sum function in python, and i am clear about it's general structure sum(iterable, start) , but i am unable to get the logic behind the following code
test = sum(5 for i in range(5) )
print("output: ", test)
output: 25
Please can anyone describe what is happening here, basically here 5 is getting multiplied with 5, and same pattern is there for every sample input.
Your code is shorthand for:
test = sum((5 for i in range(5)))
The removal of extra parentheses is syntactic sugar: it has no impact on your algorithm.
The (5 for i in range(5)) component is a generator expression which, on each iteration, yields the value 5. Your generator expression has 5 iterations in total, as defined by range(5). Therefore, the generator expression yields 5 exactly 5 times.
sum, as the docs indicate, accepts any iterable, even those not held entirely in memory. Generators, and by extension generator expressions, are memory efficient. Therefore, your logic will sum 5 exactly 5 times, which equals 25.
A convention when you don't use a variable in a closed loop is to denote that variable by underscore (_), so usually you'll see your code written as:
test = sum(5 for _ in range(5))
You can add a list to the sum function so you can make something like this:
test = sum((1,23,5,6,100))
print("output: ", test)
And you get 135.
So with your "for loop" you get a list and put that list to the sum function and you get the sum of the list. The real sum function uses yield insight and use every value and sum them up.
Basically, it is summing 5 repeativily for every "i" on range(5). Meaning, this code is equivalent to n*5, being n the size of range(n).
This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
What's going on here? I'm trying to create a list of functions:
def f(a,b):
return a*b
funcs = []
for i in range(0,10):
funcs.append(lambda x:f(i,x))
This isn't doing what I expect. I would expect the list to act like this:
funcs[3](3) = 9
funcs[0](5) = 0
But all the functions in the list seem to be identical, and be setting the fixed value to be 9:
funcs[3](3) = 27
funcs[3](1) = 9
funcs[2](6) = 54
Any ideas?
lambdas in python are closures.... the arguments you give it aren't going to be evaluated until the lambda is evaluated. At that time, i=9 regardless, because your iteration is finished.
The behavior you're looking for can be achieved with functools.partial
import functools
def f(a,b):
return a*b
funcs = []
for i in range(0,10):
funcs.append(functools.partial(f,i))
Yep, the usual "scoping problem" (actually a binding-later-than-you want problem, but it's often called by that name). You've already gotten the two best (because simplest) answers -- the "fake default" i=i solution, and functools.partial, so I'm only giving the third one of the classic three, the "factory lambda":
for i in range(0,10):
funcs.append((lambda i: lambda x: f(i, x))(i))
Personally I'd go with i=i if there's no risk of the functions in funcs being accidentally called with 2 parameters instead of just 1, but the factory function approach is worth considering when you need something a little bit richer than just pre-binding one arg.
There's only one i which is bound to each lambda, contrary to what you think. This is a common mistake.
One way to get what you want is:
for i in range(0,10):
funcs.append(lambda x, i=i: f(i, x))
Now you're creating a default parameter i in each lambda closure and binding to it the current value of the looping variable i.
All the lambdas end up being bound to the last one. See this question for a longer answer:
How do I create a list of Python lambdas (in a list comprehension/for loop)?
Considering the final value of i == 9
Like any good python function, it's going to use the value of the variable in the scope it was defined. Perhaps lambda: varname (being that it is a language construct) binds to the name, not the value, and evaluates that name at runtime?
Similar to:
i = 9
def foo():
print i
i = 10
foo()
I'd be quite interested in finding out of my answer is correct