是否可以创建一个 returns 在创建时而不是在调用函数时生成静态值的函数?
Is it possible to create a function that returns a static value generated upon creation, not upon calling the function?
问题陈述:
如何创建一个函数来传递在创建函数时确定的值,而不是在调用函数时确定的值?
背景
使用 altair
I am trying to set up multiple themes, and in order to create a theme, I need to "register" 代码如下:
def black_marks():
return {
'config': {
'mark': {
'color': 'black',
'fill': 'black'
}
}
}
# register the custom theme under a chosen name
alt.themes.register('black_marks', black_marks)
# enable the newly registered theme
alt.themes.enable('black_marks')
此时,由于 'black_marks'
已 registerd 和 enabled,任何以后使用 altair
将包括这些默认值。
注意函数black_marks
return是一个dict
,它是需要注册的函数
问题
我有几个主题想同时设置,所以我在我的代码中通过这些配置创建了一个循环:
for theme_name, theme_dict in mythemes.items():
themes.register(theme_name, lambda: theme_dict)
然后我发现在调用themes.register
函数时实际上没有注册主题。相反,它是“懒惰地”处理的。
例如,假设主题键是:['light', 'dark', 'paper']
。完成上面的循环后,我发现所有 3 个主题名称都已 注册 (例如,我可以 alt.themes.enable('light')
),但 它们都是指向最后一个,paper
。发生这种情况是因为 theme_dict
在最后一轮中确实指向与 paper
相关的主题。
渴望
我想做的是能够以某种方式“硬编码”theme_dict
指向的内容,以便 themes.register
指向一个包含生成的字典的函数每次通过。但无论我如何尝试思考这个问题,我都无法让 lambda 函数创建一个“一成不变”的函数。相反,该函数将只是 return 最后一次迭代中的任何内容。
因此,虽然这是 类 一个 altair
特定问题,但我觉得解决方案应该是通用的:
如何创建一个函数,该函数将传递在创建函数时确定的值,而不是在调用函数时确定的值?
更完整的例子
根据评论中的要求,这是我的代码的更完整快照:
for theme_key, theme_file in THEME_FILES.items(): # THEME_FILES is a dictionary with values containing file paths
with open(theme_file) as theme_fh:
raw_theme = toml.load(theme_fh)
dims = {
"width": raw_theme.pop("width"),
"height": raw_theme.pop("height"),
}
raw_theme["view"] = dims
final_theme["config"] = raw_theme
themes.register(theme_key, lambda: final_theme)
(为可怜的变量名道歉...我对我遇到的问题感到沮丧,重命名时认为这个问题是对全局变量的意外覆盖。)
再次说明一下,theme_key
已正确注册。例如,如果不同的键是 ['light', 'dark', 'paper']
,那么我可以看到所有 3 个。但是所有三个都指向上一次迭代制作的主题。在这种情况下,'paper'
主题。
如果我只是重复其中的一个主题,它就可以完美地工作。所以我相当有信心我已经查明了问题所在。
您可以使用工厂函数来生成 returns 主题字典的函数。字典将在返回函数的闭包中被捕获。
def factory(x):
def theme():
return x
return theme
for theme_name, theme_dict in mythemes.items():
themes.register(theme_name, factory(theme_dict))
如果我对问题的理解正确,这应该会产生预期的效果:
themes.register(theme_name, lambda theme_dict=theme_dict: theme_dict)
问题陈述:
如何创建一个函数来传递在创建函数时确定的值,而不是在调用函数时确定的值?
背景
使用 altair
I am trying to set up multiple themes, and in order to create a theme, I need to "register" 代码如下:
def black_marks():
return {
'config': {
'mark': {
'color': 'black',
'fill': 'black'
}
}
}
# register the custom theme under a chosen name
alt.themes.register('black_marks', black_marks)
# enable the newly registered theme
alt.themes.enable('black_marks')
此时,由于 'black_marks'
已 registerd 和 enabled,任何以后使用 altair
将包括这些默认值。
注意函数black_marks
return是一个dict
,它是需要注册的函数
问题
我有几个主题想同时设置,所以我在我的代码中通过这些配置创建了一个循环:
for theme_name, theme_dict in mythemes.items():
themes.register(theme_name, lambda: theme_dict)
然后我发现在调用themes.register
函数时实际上没有注册主题。相反,它是“懒惰地”处理的。
例如,假设主题键是:['light', 'dark', 'paper']
。完成上面的循环后,我发现所有 3 个主题名称都已 注册 (例如,我可以 alt.themes.enable('light')
),但 它们都是指向最后一个,paper
。发生这种情况是因为 theme_dict
在最后一轮中确实指向与 paper
相关的主题。
渴望
我想做的是能够以某种方式“硬编码”theme_dict
指向的内容,以便 themes.register
指向一个包含生成的字典的函数每次通过。但无论我如何尝试思考这个问题,我都无法让 lambda 函数创建一个“一成不变”的函数。相反,该函数将只是 return 最后一次迭代中的任何内容。
因此,虽然这是 类 一个 altair
特定问题,但我觉得解决方案应该是通用的:
如何创建一个函数,该函数将传递在创建函数时确定的值,而不是在调用函数时确定的值?
更完整的例子
根据评论中的要求,这是我的代码的更完整快照:
for theme_key, theme_file in THEME_FILES.items(): # THEME_FILES is a dictionary with values containing file paths
with open(theme_file) as theme_fh:
raw_theme = toml.load(theme_fh)
dims = {
"width": raw_theme.pop("width"),
"height": raw_theme.pop("height"),
}
raw_theme["view"] = dims
final_theme["config"] = raw_theme
themes.register(theme_key, lambda: final_theme)
(为可怜的变量名道歉...我对我遇到的问题感到沮丧,重命名时认为这个问题是对全局变量的意外覆盖。)
再次说明一下,theme_key
已正确注册。例如,如果不同的键是 ['light', 'dark', 'paper']
,那么我可以看到所有 3 个。但是所有三个都指向上一次迭代制作的主题。在这种情况下,'paper'
主题。
如果我只是重复其中的一个主题,它就可以完美地工作。所以我相当有信心我已经查明了问题所在。
您可以使用工厂函数来生成 returns 主题字典的函数。字典将在返回函数的闭包中被捕获。
def factory(x):
def theme():
return x
return theme
for theme_name, theme_dict in mythemes.items():
themes.register(theme_name, factory(theme_dict))
如果我对问题的理解正确,这应该会产生预期的效果:
themes.register(theme_name, lambda theme_dict=theme_dict: theme_dict)