Python enclosing scope variables with lambda function

2024/9/23 9:21:46

I wrote this simple code:

def makelist():L = []for i in range(5):L.append(lambda x: i**x)return L

ok, now I call

mylist = makelist()

because the enclosing scope variable is looked up when the nested functions are later called, they all effectively remember the same value: because of this, I expected to find the value the loop variable had on the last loop iteration, but when I check my list I see:

>>> mylist[0](0)
1
>>> mylist[0](1)
4
>>> mylist[0](2)
16
>>> 

I'm so confused, why my code doesn't retain the last for loop values? Why I don't have to explicitly retain enclosing scope values with default arguments like this:

L.append(lambda x, i=i: i ** x)

Thanks in advance

Answer

Even though i takes multiple values over time, there is effectively only one variable, i. The content of i is being changed during the loop. But the closures captures variables, not values. Nothing is evaluated inside the lambda until you call it. At the time you call the function, you access the current value of i, which happens to be the last one.

As for why i=i solves the problem, this is explained for example in The Hitchhiker's guide to Python (Common Gotchas):

Python’s default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby). This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.

And so, each fresh binding that occurs inside the closure you create (and happen to be named i just like the one outside) has its default value being computed when creating the closure. Consequently, you have the "right" value in place, ready to be used when the closure is called.

https://en.xdnf.cn/q/71838.html

Related Q&A

Overloading + to support tuples

Id like to be able to write something like this in python:a = (1, 2) b = (3, 4) c = a + b # c would be (4, 6) d = 3 * b # d would be (9, 12)I realize that you can overload operators to work with custom…

Extracting particular text associated value from an image

I have an image, and from the image I want to extract key and value pair details.As an example, I want to extract the value of "MASTER-AIRWAYBILL NO:" I have written to extract the entire te…

Installing pip in Pycharm 2016.3

I upgraded to the new version of Pycharm. In the terminal, it says bash-3.2$ instead of my username. When I tried to install a library, it said that pip command is not found:bash: pip: command not foun…

How to store real-time chat messages in database?

I am using mysqldb for my database currently, and I need to integrate a messaging feature that is in real-time. The chat demo that Tornado provides does not implement a database, (whereas the blog does…

Selectively import from another Jupyter Notebook

I arranged my Jupyter notebooks into: data.ipynb, methods.ipynb and results.ipynb. How can I selectively import cells from data and methods notebooks for use in the results notebook?I know of nbimport…

supervisord event listener

Im trying to configure an event listener for supervisord but cant get it to work. I just want to listen for PROCESS_STATE changes and run some python code triggering an urllib2request.In my .conf I hav…

Integration of Java and Python Code in One Eclipse Project

I am writing a compiler in Python using Eclipse with PyDev. Ive come to a stage where I needed to write some code in Java. Im wandering if there is a way of combining these into a single project, bec…

formatting of timestamp on x-axis

Im trying to format the x-axis in my weather data plot. Im happy with the y-axis but all my tries to get the x-axis into a decent, human-readable format didnt work so far. So after several hours of tri…

How can I set the row height in Tkinter TreeView?

I wrote a small app recently that needs to be cross-platform. I used Python and Tkinter for the GUI.It works great but recently I got a new laptop with a hiDPI screen and it seems to mess up the TreeVi…

Is replace row-wise and will overwrite the value within the dict twice?

Assuming I have following data set lst = [u, v, w, x, y] lst_rev = list(reversed(lst)) dct = dict(zip(lst, lst_rev))df = pd.DataFrame({A:[a, b, a, c, a],B:lst},dtype=category)Now I want to replace the …