This question already has answers here:
Using map() function with keyword arguments
(5 answers)
Closed 4 years ago.
I am trying to identify how we can pass in the default arguments that have been defined for a function when it is used in map
For example for the following snippet:
def func1(a,x=3,y=2):
return (a + x)*y
lst = [1,2,3]
print map(func1,lst)
Is there a way to override the values for x & y so that for each element of lst x=4 and y=3 without using lambda or list comprehension?
One way to achieve this (not mentioned in the duplicate target, and slightly less relevant there) is to use a nested function, where the outer function sets the values and returns the inner function, which is what is then executed in the map:
def func1(x=3,y=2):
def inner(a):
return (a + x)*y
return inner
lst = [1, 2, 3]
print map(func1(), lst)
print map(func1(x=4, y=3), lst)
Note the added () even if you don't want to overwrite the default arguments, otherwise it will apply the outer function to every element of lst.
The outer function is basically a function factory that produces inner functions with correctly set parameters.
Related
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 years ago.
I have a back-ground of C++ and trying to learn some python.
Whilst i understand virtual functions for C++, I unfortunately do not understand what is meant by late binding of closures in python.
Link: https://gist.github.com/deemson/8efabf56d67623ead804 (no longer works)
Copy-pasted from a tutorial:
functions = []
for n in [1, 2, 3]:
def func(x):
return n*x
functions.append(func)
# You would expect this to print [2, 4, 6]
print(
'calling a list of bad closures and output is: {}'
.format(str([function(2) for function in functions]))
)
What exactly is happening here? When the function is appended in to the list, what values does it have? Can someone please simplify this code for me to understand?
Notice this, you can create functions on runtime, more or less like lambdas in c++. So basically you are iterating over a list, making n take values 1,2 and 3
for n in [1, 2, 3]:
def func(x):
return n*x
so, by each iteration you are building a function named func, with takes a value and multiplies it for n. By appending it to the functions list you will have this functions stored, so you can iterate over the list to call the functions.
[function(2) for function in functions]
By doing this you call each of the functions stored with the value 2, you would expect this to output [2, 4, 6] ([1*2, 2*2, 3*2]), but instead it returns [6, 6, 6], WHY?, thats because every function use n for its computation, so they are not really doing 1*x, 2*x and 3*x but actually n*x and since n is bonded in last time to 3 all functions are doing 3*2 which becomes 6.
Play around with the python console to check it properly.
In the language of C++, a pointer to the function is what's being appended to the list. After the for loop, functions contains pointers to three different functions (func(x) = n * x, func(x) = n * x and func(x) = n * x). Note the dependency on n. As n changes, so will the behavior of these functions, and they are all equivalent.
In the second part of the code, the pointers are extracted from the list and each of the three functions is evaluated with an argument of 2.
Here's a further example to clarify. Imagine we do this:
>>> functions
[<function func at 0x0239AA70>, <function func at 0x0239AAB0>, <function func at 0x0239AB30>]
>>> g = functions[2]
>>> g
<function func at 0x0239AB30>
>>> g(10)
20
>>> g(100)
200
What we're seeing in that first lines is that functions contains pointers to three different functions. The next line extracts the third pointer from the list (which refers to func(x) = n * x) and assigns it to g. Effectively, we have defined a function g(x) = n * x with this call. We can now evaluate g with arguments.
Note that since all functions depend on n, you could change n, and the behavior would change.
>>> n = 100
>>> g(10)
1000
This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
What do lambda function closures capture?
(7 answers)
Closed 6 months ago.
This is so weird, if I make a list of lambda functions and with a for, I print the output of each function, everything works, but if I individually print the output of a single function like the first one, it gives me the output of the last function or I don't even know what it gives me, for example:
X = [1,2,3,4]
L = []
for i in range(len(X)):
L.append(lambda x: X[i]**x)
for i in range(len(X)):
print(L[i](2))
This gives me:
1
4
9
16
That is correct, but if i want only the first one:
print(L[0](2))
# -> 16
And if I want the second one does the same, and so on, I checked the lambda functions were all different and they are. I don't know what's going on
The lambda references the global variable i, so after the for loop, i==3, computing X[3]**2:
X = [1,2,3,4]
L = []
for i in range(len(X)):
L.append(lambda x: X[i]**x)
for f in L:
print(f(2))
Output:
16
16
16
16
A way to fix is to capture the current value of global i as a local parameter i when the function is defined:
X = [1,2,3,4]
L = []
for i in range(len(X)):
L.append(lambda x, i=i: X[i]**x) # capture i as a parameter
for f in L:
print(f(2))
Output:
1
4
9
16
You are expecting the value of i to be part of the function, not the name. That's not how function definitions work, either with def statements or lambda expressions.
I'd recommend defining a function maker, so that your expected function can close over the local value of i.
def make_function(i):
return lambda x: X[i]*x*x
Now i refers not to a global variable i, but to a local variable i in the function call. Every call to make_function creates a different local variable initialized with the value of the argument, and that variable is what your function will refer to when it is called.
for i in range(len(X)):
L.append(make_function(i))
Your lambda closes around the variable i. Despite what the for loops make it look like, there's actually only one variable i in your entire code, so when you call L[i](2) or L[0](2), you're using the current value of i. Let's look at your first example.
for i in range(len(X)):
print(L[i](2))
Here, we call L[i] with the enclosing value of i, so this is really basically
for i in range(len(X)):
print(X[i] ** 2)
On the other hand, in your second example
print(L[0](2))
The i value is the i from the final loop iteration above. To get around this, you need to explicitly capture the current value of i.
L.append(lambda x, i=i: X[i]**x)
This exploits one of Python's least intuitive features to explicitly capture a value in a lambda.
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.
This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 5 years ago.
I'm fairly new at Python and i cannot wrap my head around the results im getting
Using the code below:
def func(a,b=set()):
res=list()
for i in a:
if i not in b:
res.append(i)
b|={i}
return res
print(func([1,1,2,2,3,4]))
print(func([1,1,2,2,3,4]))
I was getting output:
[1,2,3,4]
[]
I put "print(b)" above "res=list()" and got output:
set()
[1,2,3,4]
{1,2,3,4}
[]
What is going on? Shouldn't "b" be set to "set()" when i call the function? Im using Python 3.6
Have a look at the documentation for default parameters:
The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes.
When you define a function with a default parameter, the default value is only evaluated when the definition is first executed by the interpreter (the actual def statement). This is usually not a problem, except for when a mutable default value is used. That is to say, one that can be modified in place.
In your case, when you modify b in your function the first time you call it, it keeps that value the next time around. To avoid this, you can do like so:
def func(a,b=None):
if b is None:
b = set()
res=list()
for i in a:
if i not in b:
res.append(i)
b|={i}
return res
Now b will always have the default value you want.
In python functions are objects and arguments are evaluated and executed once. this is a nice explanation : http://effbot.org/zone/default-values.htm
in your example, it could be "fixed" by doing:
def func(a,b=None):
if b is None:
b = set()
res=list()
for i in a:
if i not in b:
res.append(i)
b|={i}
return res
In First function call b is empty
See here
In second function call b is already fill with element
So this condition not run if i not in b and return empty list
Try this
def func(a):
res=list()
b=set()
for i in a:
if i not in b:
res.append(i)
b|={i}
return res
print(func([1,1,2,2,3,4]))
print(func([1,1,2,2,3,4]))
Output
[1, 2, 3, 4]
[1, 2, 3, 4]
This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
Below is an example I got from someone's blog about python closure.
I run it in python 2.7 and get a output different from my expect.
flist = []
for i in xrange(3):
def func(x):
return x*i
flist.append(func)
for f in flist:
print f(2)
My expected output is: 0, 2, 4
But the output is: 4, 4, 4
Is there anyone could help to explain it?
Thank you in advance.
Loops do not introduce scope in Python, so all three functions close over the same i variable, and will refer to its final value after the loop finishes, which is 2.
It seems as though nearly everyone I talk to who uses closures in Python has been bitten by this. The corollary is that the outer function can change i but the inner function cannot (since that would make i a local instead of a closure based on Python's syntactic rules).
There are two ways to address this:
# avoid closures and use default args which copy on function definition
for i in xrange(3):
def func(x, i=i):
return x*i
flist.append(func)
# or introduce an extra scope to close the value you want to keep around:
for i in xrange(3):
def makefunc(i):
def func(x):
return x*i
return func
flist.append(makefunc(i))
# the second can be simplified to use a single makefunc():
def makefunc(i):
def func(x):
return x*i
return func
for i in xrange(3):
flist.append(makefunc(i))
# if your inner function is simple enough, lambda works as well for either option:
for i in xrange(3):
flist.append(lambda x, i=i: x*i)
def makefunc(i):
return lambda x: x*i
for i in xrange(3):
flist.append(makefunc(i))
You are not creating closures. You are generating a list of functions which each access the global variable i which is equal to 2 after the first loop. Thus you end up with 2 * 2 for each function call.
Each function accesses the global i.
functools.partial comes to rescue:
from functools import partial
flist = []
for i in xrange(3):
def func(x, multiplier=None):
return x * multiplier
flist.append(partial(func, multiplier=i))