问题
Consider this (rather pointless) javascript code:
function make_closure() {
var x = 123, y = 456;
return function(varname) { return eval(varname) }
}
closure = make_closure()
closure("x") // 123
closure("y") // 456
The function returned from make_closure
doesn't contain any references to scope variables, but still is able to return their values when called.
Is there a way to do the same in python?
def make_closure():
x = 123
return lambda varname: ...no "x" here...
closure = make_closure()
print closure("x") # 123
In other words, how to write a closure that would "know" about variables in defining scope without mentioning them explicitly?
回答1:
This is probably the closest thing to an exact equivalent:
def make_closure():
x = 123
l = locals()
return lambda(varname): eval(varname, None, l)
closure = make_closure()
print closure("x") # 123
Ultimately, your problem isn't that x wasn't captured by your local closure, but that your local scope wasn't passed into eval.
See http://docs.python.org/library/functions.html#eval for details on the eval function.
It probably goes without saying that this is not a very Pythonic thing to do. You almost never actually want to call eval in Python; if you think you do, step back and rethink your larger design. But when you do need to use it, you need to understand how it's different from Javascript eval. It's ultimately more powerful—it can be used to simulate dynamic scoping, or as a simplified version of exec, or to evaluate code in any arbitrarily-constructed environment—but that also means it's trickier.
回答2:
People have already mentioned using locals()
. Another, admittedly less flexible, approach is to use the new nonlocal
keyword in Python 3:
>>> def make_closure():
... x = 123
... def return_var(varname):
... nonlocal x
... return eval(varname)
... return return_var
...
>>> closure = make_closure()
>>> closure("x")
123
This has the obvious downside of requiring you to explicitly label the variables from the outer scope that you wish to close over and reference.
回答3:
You can close around variables in Python, approximately how you would in Javascript:
def foo():
x = 123
return lambda y: x+y
q = foo()
print q(5)
http://ideone.com/Q8iBg
However, there are some differences - for instance, you can't write to variables in the parent's scope (trying to write just creates a local-scoped variable instead). Also, Python's eval()
doesn't include parent scopes.
You can bypass this for eval()
by explicitly grabbing the locals from the parent scope and passing them into the child's eval()
as its locals argument, but the real question here is why do you need to do this?
回答4:
In Python 2.x this requires some massive kludging. However, in Python 3.x the 'nonlocal' keyword was introduced to allow access to variables in the immediately enclosing scope.
It might be worth checking here for further information: nonlocal keyword in Python 2.x
来源:https://stackoverflow.com/questions/11110304/auto-bind-scope-variables-in-a-closure