我需要通过for循环定义python lambda函数的字典。每个lambda函数都需要相对字典键的值才能起作用,但我希望避免将此类键作为参数传递。这是我的问题的虚拟版本。
给定
a = {'bar': 0, 'foo': 1} # a reference dictionary
dic1 = {'bar': lambda x: x['bar'], 'foo': lambda x: x['foo']}
dic2 = {key: lambda x: x[key] for key in a}
Run Code Online (Sandbox Code Playgroud)
我希望dic1和dic2做同样的事情,但是只有dic1会按照我的意愿进行操作。特别是
print(dic1['bar'](a), dic1['foo'](a))
print(dic2['bar'](a), dic2['foo'](a))
Run Code Online (Sandbox Code Playgroud)
是
0 1
1 1
Run Code Online (Sandbox Code Playgroud)
代替
0 1
0 1
Run Code Online (Sandbox Code Playgroud)
它不起作用的原因与Python中的后期绑定闭包有关。
Python的闭包是后期绑定。这意味着在调用内部函数时会查询闭包中使用的变量的值。
Adapting the source explanation, whenever the return function is called, the value of key is looked up in the surrounding scope at call time. By then, the loop has completed and key is left with its final value of 'foo'.
You can resolve this by creating a closure that binds immediately to its arguments by using a default arg like so:
a = {'bar': 0, 'foo': 1} # a reference dictionary
dic1 = {'bar': lambda x: x['bar'], 'foo': lambda x: x['foo']}
dic2 = {key: lambda x, key=key: x[key] for key in a}
print(dic1['bar'](a), dic1['foo'](a))
print(dic2['bar'](a), dic2['foo'](a))
Run Code Online (Sandbox Code Playgroud)
Result:
0 1
0 1
Run Code Online (Sandbox Code Playgroud)