Scope of lambda functions and their parameters? [duplicate]
I need a callback function that is almost exactly the same for a series of gui events. The function will behave slightly differently depending on which event has called it. Seems like a simple case to me, but I cannot figure out this weird behavior of lambda functions.
So I have the following simplified code below:
def callback(msg):
print msg
#creating a list of function handles with an iterator
funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(lambda: callback(m))
for f in funcList:
f()
#create one at a time
funcList=[]
funcList.append(lambda: callback('do'))
funcList.append(lambda: callback('re'))
funcList.append(lambda: callback('mi'))
for f in funcList:
f()
The output of this code is:
mi
mi
mi
do
re
mi
I expected:
do
re
mi
do
re
mi
Why has using an iterator messed things up?
I've tried using a deepcopy:
import copy
funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(lambda: callback(copy.deepcopy(m)))
for f in funcList:
f()
But this has the same problem.
Asked by: Tara261 | Posted: 27-01-2022
Answer 1
When a lambda is created, it doesn't make a copy of the variables in the enclosing scope that it uses. It maintains a reference to the environment so that it can look up the value of the variable later. There is just one m
. It gets assigned to every time through the loop. After the loop, the variable m
has value 'mi'
. So when you actually run the function you created later, it will look up the value of m
in the environment that created it, which will by then have value 'mi'
.
One common and idiomatic solution to this problem is to capture the value of m
at the time that the lambda is created by using it as the default argument of an optional parameter. You usually use a parameter of the same name so you don't have to change the body of the code:
for m in ('do', 're', 'mi'):
funcList.append(lambda m=m: callback(m))
Answered by: Kelvin601 | Posted: 28-02-2022
Answer 2
The problem here is the m
variable (a reference) being taken from the surrounding scope.
Only parameters are held in the lambda scope.
To solve this you have to create another scope for lambda:
def callback(msg):
print msg
def callback_factory(m):
return lambda: callback(m)
funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(callback_factory(m))
for f in funcList:
f()
In the example above, lambda also uses the surounding scope to find m
, but this
time it's callback_factory
scope which is created once per every callback_factory
call.
Or with functools.partial:
from functools import partial
def callback(msg):
print msg
funcList=[partial(callback, m) for m in ('do', 're', 'mi')]
for f in funcList:
f()
Answered by: Eric527 | Posted: 28-02-2022
Answer 3
Python does uses references of course, but it does not matter in this context.
When you define a lambda (or a function, since this is the exact same behavior), it does not evaluate the lambda expression before runtime:
# defining that function is perfectly fine
def broken():
print undefined_var
broken() # but calling it will raise a NameError
Even more surprising than your lambda example:
i = 'bar'
def foo():
print i
foo() # bar
i = 'banana'
foo() # you would expect 'bar' here? well it prints 'banana'
In short, think dynamic: nothing is evaluated before interpretation, that's why your code uses the latest value of m.
When it looks for m in the lambda execution, m is taken from the topmost scope, which means that, as others pointed out; you can circumvent that problem by adding another scope:
def factory(x):
return lambda: callback(x)
for m in ('do', 're', 'mi'):
funcList.append(factory(m))
Here, when the lambda is called, it looks in the lambda' definition scope for a x. This x is a local variable defined in factory's body. Because of this, the value used on lambda execution will be the value that was passed as a parameter during the call to factory. And doremi!
As a note, I could have defined factory as factory(m) [replace x by m], the behavior is the same. I used a different name for clarity :)
You might find that Andrej Bauer got similar lambda problems. What's interesting on that blog is the comments, where you'll learn more about python closure :)
Answered by: Brianna482 | Posted: 28-02-2022Answer 4
Yes, that's a problem of scope, it binds to the outer m, whether you are using a lambda or a local function. Instead, use a functor:
class Func1(object):
def __init__(self, callback, message):
self.callback = callback
self.message = message
def __call__(self):
return self.callback(self.message)
funcList.append(Func1(callback, m))
Answered by: Marcus206 | Posted: 28-02-2022
Answer 5
the soluiton to lambda is more lambda
In [0]: funcs = [(lambda j: (lambda: j))(i) for i in ('do', 're', 'mi')]
In [1]: funcs
Out[1]:
[<function __main__.<lambda>>,
<function __main__.<lambda>>,
<function __main__.<lambda>>]
In [2]: [f() for f in funcs]
Out[2]: ['do', 're', 'mi']
the outer lambda
is used to bind the current value of i
to j
at the
each time the outer lambda
is called it makes an instance of the inner lambda
with j
bound to the current value of i
as i
's value
Answer 6
First, what you are seeing is not a problem, and not related to call-by-reference or by-value.
The lambda syntax you defined has no parameters, and as such, the scope you are seeing with parameter m
is external to the lambda function. This is why you are seeing these results.
Lambda syntax, in your example is not necessary, and you would rather be using a simple function call:
for m in ('do', 're', 'mi'):
callback(m)
Again, you should be very precise about what lambda parameters you are using and where exactly their scope begins and ends.
As a side note, regarding parameter passing. Parameters in python are always references to objects. To quote Alex Martelli:
Answered by: Aston814 | Posted: 28-02-2022The terminology problem may be due to the fact that, in python, the value of a name is a reference to an object. So, you always pass the value (no implicit copying), and that value is always a reference. [...] Now if you want to coin a name for that, such as "by object reference", "by uncopied value", or whatever, be my guest. Trying to reuse terminology that is more generally applied to languages where "variables are boxes" to a language where "variables are post-it tags" is, IMHO, more likely to confuse than to help.
Answer 7
The variable m
is being captured, so your lambda expression always sees its "current" value.
If you need to effectively capture the value at a moment in time, write a function takes the value you want as a parameter, and returns a lambda expression. At that point, the lambda will capture the parameter's value, which won't change when you call the function multiple times:
def callback(msg):
print msg
def createCallback(msg):
return lambda: callback(msg)
#creating a list of function handles with an iterator
funcList=[]
for m in ('do', 're', 'mi'):
funcList.append(createCallback(m))
for f in funcList:
f()
Output:
do
re
mi
Answered by: Sophia816 | Posted: 28-02-2022
Answer 8
there are actually no variables in the classic sense in Python, just names that have been bound by references to the applicable object. Even functions are some sort of object in Python, and lambdas do not make an exception to the rule :)
Answered by: Vivian508 | Posted: 28-02-2022Answer 9
As a side note, map
, although despised by some well known Python figure, forces a construction which prevents this pitfall.
fs = map (lambda i: lambda: callback (i), ['do', 're', 'mi'])
NB : the first lambda i
acts like the factory in other answers.
Similar questions
How do Python functions handle the types of parameters that you pass in?
Unless I'm mistaken, creating a function in Python works like this:
def my_func(param1, param2):
# stuff
However, you don't actually give the types of those parameters. Also, if I remember, Python is a strongly typed language, as such, it seems like Python shouldn't let you pass in a parameter of a different type than the function creator expected. However, how does Python know that t...
Python parameters and functions
I just started learning Python and I've just been messing around typing different codes for practice to learn, and I made this code:
import math
def lol():
print (math.cos(math.pi))
print ("I hope this works")
def print_twice(bruce):
print bruce
print bruce
print_twice(lol())
When I run it, my output is:
-1.0
I hope this works
None
None
...
Functions and parameters in python 2.7.3
In my Computer Science class, I am just starting to learn about Functions and parameters in python. Right now my instructor is making us learn parameter passing. Instead of typing a huge summarization of my program I just retyped the assignment guide down below.
Description: In this program the user will have to option of entering a charge, entering a payment or displaying the balance on their c...
Trying to pass parameters as functions in Python
I have this:
class Student:
def __init__(self, FirstName, LastName):
self.FirstName = FirstName
self.LastName = LastName
def __iter__(self):
return self
Students = [
# FirstName LastName
Student("Mary", "Smith"),
Student("Joe", "Jones"),
Student("Jane", "Doe" )]
I make a Student...
python - list of functions with parameters
I need to obtain a list of functions, where my function is defined as follows:
import theano.tensor as tt
def tilted_loss(y,f,q):
e = (y-f)
return q*tt.sum(e)-tt.sum(e[e<0])
I attempted to do
qs = np.arange(0.05,1,0.05)
q_loss_f = [tilted_loss(q=q) for q in qs]
however, get the error TypeError: tilted_loss() missing 2 required positional...
Python nested functions for same parameters
i have 2 python list and i want to calculate 4 different values using different functions(TP, TN, FP, FN). its better if i can define parameters in outer nested function without defining parameters for each and every functions as parameters are same for all 4 functions.
i have implemented a function, but it gives only the TP function output. could you please someone help me to find the issue here
def evalua...
Python functions and array parameters
I am trying to build a program that can produce (x,y,z) 10x10x10 arrays (unit cells) on a 3D grid. Example: one cube is at point (0,10)x(0,10)x(0,10) while another is at (0,10)x(10,20)x(0,10). So far I have a function that makes 4 of these but how would I automate it to make dozens or even hundreds?
import math
import numpy as np
def cubeplot():
count = 0
count2 = 0
x = 11
y = 11
z = ...
python - How to unit test time based functions without adding parameters
I created a function that returns seconds left until the next occurrence of that time, but I came across a problem writing a unit test for it. How do people test this type of function that has a call to datetime.now() in it?
Adding another parameter (current_time) seems wrong just to test it as it changes the initial requirements of the function.
function to test is.
numpy - match a list of functions against a list of parameters in python
I have a list of different polynoms created with np.poly1d:
polys = [p1,p2,...,pn]
and I want to know the values that take these polynoms for specific parameters:
xs = [8.1, 2.3, ..., 4.2] #nvalues
The results I want is:
ys = [p1(8.1), p2(2.3), ..., pn(4.2)] #I want the numeric values.
Can you store functions with parameters in a list and call them later in Python?
For example, when I have:
def function(text):
print(text)
mylist = [function('yes'),function('no')]
mylist[0]
It just prints yes and no and doesn't do anything with mylist[0].
I want it to be able to call the function with parameters in the list and not have the functions run when the program starts. Is this possible?
python - Using parameters to pass values between functions
I am currently having an issue, as i am relatively new to python , it might be a very easy solution for others.
I want to pass a parameter between both functions 'eg1' and 'eg2', there is a common number the user will input (example:10) then 'eg1' will add 1 to it and 'eg2' will take the final value of 'eg1' and add 1 more to it, (example: 10 will become 11 then 12)
It is troubling me because this keeps po...
python - How to pass parameters between functions?
Closed. This question needs to be more focused. It ...
How to use a list of lists as parameters for functions in Python
I'm trying to write a function that will automatically calculate equivalent vectors, but I get an error.
def vector(lst):
import math
Sfy , Sfx = 0
for i in lst:
fy = i[0]/math.sin(i[1])
fx = i[0]/math.cos(i[1])
if 90 < i[1] < 180:
fx = -1*fx
if 180 <= i[1] <= 270:
fx = -1*fx
fy = -1*fy
if 270 < i[1] < 360:
fy = -1*fy
print(fx , fy)...
python - Define input parameters for all pytest functions
I have a large Python project with many functions that are used by a single driver main.py. The driver provides the input parameters needed for all the functions. I'm using pytest to test the functions. A basic example of such a project is given below. In the example, parameters are defined as s, t, x, y, z, a, b, c, j, k.
# main.py
# -----------...
How do Python functions handle the types of parameters that you pass in?
Unless I'm mistaken, creating a function in Python works like this:
def my_func(param1, param2):
# stuff
However, you don't actually give the types of those parameters. Also, if I remember, Python is a strongly typed language, as such, it seems like Python shouldn't let you pass in a parameter of a different type than the function creator expected. However, how does Python know that t...
python - Optional parameters in functions and their mutable default values
This question already has answers here:
Python parameters and functions
I just started learning Python and I've just been messing around typing different codes for practice to learn, and I made this code:
import math
def lol():
print (math.cos(math.pi))
print ("I hope this works")
def print_twice(bruce):
print bruce
print bruce
print_twice(lol())
When I run it, my output is:
-1.0
I hope this works
None
None
...
easy functions with multiple parameters Python 2.7
I'm learning with Zelle's Python Programming and got stuck a little bit on functions.
We got this:
def addInterest(balance, rate):
newBalance = balance * (1+rate)
balance = newBalance
def test():
amount = 1000
rate = 0.05
addInterest(amount, rate)
print amount
test()
This code fails to print 1050 as output. But the below succeedes:
def a...
Functions and parameters in python 2.7.3
In my Computer Science class, I am just starting to learn about Functions and parameters in python. Right now my instructor is making us learn parameter passing. Instead of typing a huge summarization of my program I just retyped the assignment guide down below.
Description: In this program the user will have to option of entering a charge, entering a payment or displaying the balance on their c...
python - Are functions evaluated when passed as parameters?
if I have some code like this:
def handler(self):
self.run(self.connect)
def connect(self, param):
#do stuff...
def run(self, connector):
self.runner = connector
What's evaluated first when I call self.run(self.connect)?
run with the stuff in connect already done? or connect with self.connect yet to be evaluated?
Trying to pass parameters as functions in Python
I have this:
class Student:
def __init__(self, FirstName, LastName):
self.FirstName = FirstName
self.LastName = LastName
def __iter__(self):
return self
Students = [
# FirstName LastName
Student("Mary", "Smith"),
Student("Joe", "Jones"),
Student("Jane", "Doe" )]
I make a Student...
python - Calling functions with various parameters using user input
This question already has answers here:
python - How do I pass parameters into functions using other functions?
I keep getting error: "unhashable type: list" for line (routing_table[key][0] = [[params], func]. I'm attempting to pass a url and function into a route function. This route function should pick out the parameters for other functions by use of regular expressions. The ultimate goal is to read in "/page/<page_id>, then pick out <page_id> and replace that with user input. That user input...
python - flask: passing parameters across view functions
How can I pass variables across views in flask
Edit : For illustrative purposes, say I have an variable that is set in user() called id. Of course this is a local variable and is not visible to user_add(). Is there a way to communicate this value with user_add in a nice way preserving the locality?
I have the following code in view:
@app.route('/users', methods=['GET', 'POST'])
def user():
...
python - Django: Arbitrary number of unnamed urls.py parameters
I have a Django model with a large number of fields and 20000+ table rows. To facilitate human readable URLs and the ability to break down the large list into arbitrary sublists, I would like to have a URL that looks like this:
/browse/<name1>/<value1>/<name2>/<value2>/ .... etc ....
where 'name' maps to a model attribute and 'value' is the search criteria for that...
python - variables as parameters in field options
I want to create a model, that will set editable=False on creation, and editable=True on editing item. I thought it should be something like this:
home = models.ForeignKey(Team, editable=lambda self: True if self.id else False)
But it doesn't work. Maybe something with overriding the init can help me, but i don't sure what can do the trick. I know i can check for self.id...
c# - How to analyse .exe parameters inside the program?
I have a program that can have a lot of parameters (we have over +30 differents options).
Example:
myProgram.exe -t alpha 1 -prod 1 2 -sleep 200
This is 3 Commands (from command pattern object at the end) that each contain some parameters. Inside the code we parse all command (start with -) and get a list of string (split all space) for the parameters. So in fact, we have : string-->Collection ...
python - Default parameters to actions with Django
Is there a way to have a default parameter passed to a action in the case where the regex didnt match anything using django?
urlpatterns = patterns('',(r'^test/(?P<name>.*)?$','myview.displayName'))
#myview.py
def displayName(request,name):
# write name to response or something
I have tried setting the third parameter in the urlpatterns to a dictionary containing ' and giving...
python - Loop function parameters for sanity check
I have a Python function in which I am doing some sanitisation of the input parameters:
def func(param1, param2, param3):
param1 = param1 or ''
param2 = param2 or ''
param3 = param3 or ''
This caters for the arguments being passed as None rather than empty strings. Is there an easier/more concise way to loop round the function parameters to apply such an expression to ...
python - How can I pass all the parameters to a decorator?
I tried to trace the execution of some methods using a decorator. Here is the decorator code:
def trace(func):
def ofunc(*args):
func_name = func.__name__
xargs = args
print "entering %s with args %s" % (func_name,xargs)
ret_val = func(args)
print "return value %s" % ret_val
print "exiting %s" % (func_nam...
parameters - Python Newbie: Returning Multiple Int/String Results in Python
I have a function that has several outputs, all of which "native", i.e. integers and strings. For example, let's say I have a function that analyzes a string, and finds both the number of words and the average length of a word.
In C/C++ I would use @ to pass 2 parameters to the function. In Python I'm not sure what's the right solution, because integers and strings are not passed by reference but by value (at leas...
Print out list of function parameters in Python
Is there a way to print out a function's parameter list?
For example:
def func(a, b, c):
pass
print_func_parametes(func)
Which will produce something like:
["a", "b", "c"]
python - How to create a decorator that can be used either with or without parameters?
I'd like to create a Python decorator that can be used either with parameters:
@redirect_output("somewhere.log")
def foo():
....
or without them (for instance to redirect the output to stderr by default):
@redirect_output
def foo():
....
Is that at all possible?
Note that I'm not looking for a different solution to the problem of redirectin...
sql - How do you make the Python Msqldb module use ? in stead of %s for query parameters?
MySqlDb is a fantastic Python module -- but one part is incredibly annoying.
Query parameters look like this
cursor.execute("select * from Books where isbn=%s", (isbn,))
whereas everywhere else in the known universe (oracle, sqlserver, access, sybase...)
they look like this
cursor.execute("select * from Books where isbn=?", (isbn,))
This means that if you ...
Still can't find your answer? Check out these communities...
PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python