Python closures and cells (closed-over values)

我的未来我决定 提交于 2019-12-07 07:27:21

问题


What is the Python mechanism that makes it so that

[lambda: x for x in range(5)][2]()

is 4?

What is the usual trick for binding a copy of x to each lamba expression so that the above expression will equal 2?


My final solution:

for template, model in zip(model_templates, model_classes):
    def create_known_parameters(known_parms):
        return lambda self: [getattr(self, p.name)
                             for p in known_parms]
    model.known_parameters = create_known_parameters(template.known_parms)

回答1:


I usually use functools.partial:

[ partial(lambda x: x, x) for x in range(5) ]

Or, of course, you can do it yourself:

[ (lambda x: (lambda: x))(x) for x in range(5) ]



回答2:


>>> [lambda x=x: x for x in range(5)][2]()
2



回答3:


Since no one's answered the "what is the mechanism" part, and this surprised me when I first read it, here's a go:

This:

ls = [lambda: x for x in range(5)]

Is a bit like this:

ls = []
x = 0
ls.append(lambda: x)
x = 1
ls.append(lambda: x)
x = 2
ls.append(lambda: x)
x = 3
ls.append(lambda: x)
x = 4
ls.append(lambda: x)

Each of those lambdas has its own scope, but none of those scopes contain an x. So they're all going to be reading the value of x by looking in an outer scope, so of course they must all be referring to the same object. By the time any of them are called, the loop is done and that object is the integer 4.

So even though these lambdas look like functions involving only immutable values, they can still be affected by side effects, because they depend on the bindings in an outer scope, and that scope can change.

You could of course further change what these lambdas return by rebinding x, or make them throw an error by unbinding it. In the list comprehension version though, the x is only bound in a private scope inside the list comprehension, so you can't mess with it (as easily).

The solution is of course to arrange things so that each lambda has an x in its local scope (or at least some outer scope that is not shared between the lambdas), so that they can all refer to different objects. Ways to do that have been shown in the other answers.



来源:https://stackoverflow.com/questions/9189702/python-closures-and-cells-closed-over-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!