如何从 lambda 中的父作用域修复当前变量值
How to fix current variable value from parent scope in lambda
我需要在运行时创建一组回调,它们使用字典中的值(每个回调一个键值对)。在 dict 循环之后,dict 丢失了,但是回调应该保持正确的值。 (这让我想起了 JavaScript 中的作用域和 clojure)
重现我的问题的简单 python 脚本:
cmds = list()
def main():
values = {'label1':'value1', 'label2':'value2'}
for l,v in values.items():
add_command(command = lambda: apply_new_item(l,v))
def apply_new_item(label, value):
print('{}: {}'.format(label, value))
def add_command(command):
cmds.append(command)
def call_actions():
for command in cmds:
command()
# Create callbacks
main()
# Check callbacks
call_actions()
如果我试图以完全错误的方式解决我的问题,我想提供一些我需要这种行为的上下文。
我有一个使用 TKinter 来创建 UI 的应用程序。应用程序应支持加载自定义实体配置,即 python 脚本本身。脚本的要求是定义一个或多个函数,这些函数提供 python 特定结构的对象(定义自定义实体)。我将用户配置文件作为 python 模块加载,并将所有具有特定名称的函数收集为自定义实体提供程序。然后我调用每个配置提供程序,将结果转换为我的内部实体配置,并想在运行时添加一个菜单项,该菜单项应该从相应的实体配置创建一个实例(实例创建涉及对随机的一些调用,所以两个实体是从相同的配置总是不同的)。
所以,我有一个具有正确值的字典(内部配置的名称),但是当我在字典的 foreach 循环中添加 TKinter 菜单项时,所有命令都指向迭代器的最后一个值:
custom_entities_menu = tk.Menu(entities_menu)
# ...
for name, cfg in custom_configs.items():
custom_entities_menu.add_command(label = name, command = lambda: self.__create_new_entity(name, cfg))
函数工具或绑定参数可能有效。我的理解是 functools 更 pythonic:
import functools
cmds = list()
def main():
values = {'label1':'value1', 'label2':'value2'}
for l,v in values.items():
add_command(command = functools.partial(apply_new_item, l,v))
def apply_new_item(label, value):
print('{}: {}'.format(label, value))
def add_command(command):
cmds.append(command)
def call_actions():
for command in cmds:
command()
# Create callbacks
main()
# Check callbacks
call_actions()
它也适用于 lambda 中的绑定参数:
cmds = list()
def main():
values = {'label1':'value1', 'label2':'value2'}
for l,v in values.items():
add_command(command = lambda l=l, v=v: apply_new_item(l,v))
def apply_new_item(label, value):
print('{}: {}'.format(label, value))
def add_command(command):
cmds.append(command)
def call_actions():
for command in cmds:
command()
# Create callbacks
main()
# Check callbacks
call_actions()
编辑:在 lambda 中添加了绑定参数
编辑:将 functools 部分移动到顶部,因为它更像 pythonic
我需要在运行时创建一组回调,它们使用字典中的值(每个回调一个键值对)。在 dict 循环之后,dict 丢失了,但是回调应该保持正确的值。 (这让我想起了 JavaScript 中的作用域和 clojure)
重现我的问题的简单 python 脚本:
cmds = list()
def main():
values = {'label1':'value1', 'label2':'value2'}
for l,v in values.items():
add_command(command = lambda: apply_new_item(l,v))
def apply_new_item(label, value):
print('{}: {}'.format(label, value))
def add_command(command):
cmds.append(command)
def call_actions():
for command in cmds:
command()
# Create callbacks
main()
# Check callbacks
call_actions()
如果我试图以完全错误的方式解决我的问题,我想提供一些我需要这种行为的上下文。 我有一个使用 TKinter 来创建 UI 的应用程序。应用程序应支持加载自定义实体配置,即 python 脚本本身。脚本的要求是定义一个或多个函数,这些函数提供 python 特定结构的对象(定义自定义实体)。我将用户配置文件作为 python 模块加载,并将所有具有特定名称的函数收集为自定义实体提供程序。然后我调用每个配置提供程序,将结果转换为我的内部实体配置,并想在运行时添加一个菜单项,该菜单项应该从相应的实体配置创建一个实例(实例创建涉及对随机的一些调用,所以两个实体是从相同的配置总是不同的)。 所以,我有一个具有正确值的字典(内部配置的名称),但是当我在字典的 foreach 循环中添加 TKinter 菜单项时,所有命令都指向迭代器的最后一个值:
custom_entities_menu = tk.Menu(entities_menu)
# ...
for name, cfg in custom_configs.items():
custom_entities_menu.add_command(label = name, command = lambda: self.__create_new_entity(name, cfg))
函数工具或绑定参数可能有效。我的理解是 functools 更 pythonic:
import functools
cmds = list()
def main():
values = {'label1':'value1', 'label2':'value2'}
for l,v in values.items():
add_command(command = functools.partial(apply_new_item, l,v))
def apply_new_item(label, value):
print('{}: {}'.format(label, value))
def add_command(command):
cmds.append(command)
def call_actions():
for command in cmds:
command()
# Create callbacks
main()
# Check callbacks
call_actions()
它也适用于 lambda 中的绑定参数:
cmds = list()
def main():
values = {'label1':'value1', 'label2':'value2'}
for l,v in values.items():
add_command(command = lambda l=l, v=v: apply_new_item(l,v))
def apply_new_item(label, value):
print('{}: {}'.format(label, value))
def add_command(command):
cmds.append(command)
def call_actions():
for command in cmds:
command()
# Create callbacks
main()
# Check callbacks
call_actions()
编辑:在 lambda 中添加了绑定参数
编辑:将 functools 部分移动到顶部,因为它更像 pythonic