Auto-bind scope variables in a closure

谁说胖子不能爱 提交于 2020-01-02 08:24:10

问题


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

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