具有字典推导式的元编程
Meta programming with dictionary comprehensions
所以我有一堆函数要用不同的参数创建。其中一个参数 df
将由这些函数的调用者提供。我以为我已经弄清楚了,但是当我实际使用它时,创建的每个函数都有相同的参数,即列表理解序列中的最后一个组合。奇怪。
from itertools import product
feature_functions = {
**{f'{col}{i}': lambda x: createFeature(df=x, i=i, col=col, name=f'{col}{i}')
for col, i in product(['New', 'Lost', 'Change'], list(range(1, 31)))},
就像我说的,我觉得这很漂亮,但是当我这样使用它时:
feature_functions['New1'](df)
我得到了这个结果,这意味着它对每个 lambda 函数使用了 'Change' 和 30:
# feature pd.Series:
0 NaN
...
4593 1.002706
Name: Change30, Length: 4594, dtype: float64
我尝试了几件事,但没有任何改变。我怎么用错了这本词典理解?
编辑:顺便说一句,我为验证它的正确性所做的一件事是将 lambda x: ...
放在引号中,然后我可以将其全部打印出来,看起来非常不错。那么,不知何故 lambda 妨碍了?我确实尝试将它包装在 (lambda x: ...)
中,但没有任何作用。
{'New1': "lambda x: createFeature(df=x, i=1, col=New, name='New1')",
'New2': "lambda x: createFeature(df=x, i=2, col=New, name='New2')",
'New3': "lambda x: createFeature(df=x, i=3, col=New, name='New3')",
'New4': "lambda x: createFeature(df=x, i=4, col=New, name='New4')",
...
}
你真的很亲近。在这里,不要使用 lambda
,而是使用 functools
模块中的 partial
函数:
# dummy function
def createFeature(df, i, col, name):
print(df)
print(i, col, name)
feature_functions = {
**{f'{col}{i}': partial(createFeature, i=i, col=col, name=f'{col}{i}')
for col, i in product(['New', 'Lost', 'Change'], list(range(1, 31)))}}
用法:
>>> feature_functions['New1'](pd.DataFrame)
Empty DataFrame
Columns: []
Index: []
1 New New1
>>> feature_functions['Lost23'](pd.DataFrame())
Empty DataFrame
Columns: []
Index: []
23 Lost Lost23
>>> feature_functions['Change12'](pd.DataFrame())
Empty DataFrame
Columns: []
Index: []
12 Change Change12
好的,这很有趣。如果你创建一个 returns 你的 lambda 的函数,例如:
def createFeatureCreator(i, col):
return lambda x: createFeature(df=x, i=i, col=col, name=f'{col}{i}')
并做你的理解(我删除了你的很多虚假内容):
feature_functions = {f'{col}{i}': createFeatureCreator(i, col)
for col, i in product(['New', 'Lost', 'Change'], range(1, 31))}
它如您所愿地工作。
“lambda”构造不能直接工作的原因实际上很有趣:lambda 捕获环境。字典理解是一个单一的环境,其中变量 i
和 col
在循环的每次迭代中都会发生变化。创建 lambda 时(实际上创建了 93 个不同的 lambda),它们都捕获相同的环境,因此当它们被执行时,i
和 col
的值是它们在环境(f 字符串扩展为函数调用,因为它在 lambda 内部而未执行,并且仅在您实际调用该函数时执行,这就是名称也显示为“错误”的原因)。
所以我有一堆函数要用不同的参数创建。其中一个参数 df
将由这些函数的调用者提供。我以为我已经弄清楚了,但是当我实际使用它时,创建的每个函数都有相同的参数,即列表理解序列中的最后一个组合。奇怪。
from itertools import product
feature_functions = {
**{f'{col}{i}': lambda x: createFeature(df=x, i=i, col=col, name=f'{col}{i}')
for col, i in product(['New', 'Lost', 'Change'], list(range(1, 31)))},
就像我说的,我觉得这很漂亮,但是当我这样使用它时:
feature_functions['New1'](df)
我得到了这个结果,这意味着它对每个 lambda 函数使用了 'Change' 和 30:
# feature pd.Series:
0 NaN
...
4593 1.002706
Name: Change30, Length: 4594, dtype: float64
我尝试了几件事,但没有任何改变。我怎么用错了这本词典理解?
编辑:顺便说一句,我为验证它的正确性所做的一件事是将 lambda x: ...
放在引号中,然后我可以将其全部打印出来,看起来非常不错。那么,不知何故 lambda 妨碍了?我确实尝试将它包装在 (lambda x: ...)
中,但没有任何作用。
{'New1': "lambda x: createFeature(df=x, i=1, col=New, name='New1')",
'New2': "lambda x: createFeature(df=x, i=2, col=New, name='New2')",
'New3': "lambda x: createFeature(df=x, i=3, col=New, name='New3')",
'New4': "lambda x: createFeature(df=x, i=4, col=New, name='New4')",
...
}
你真的很亲近。在这里,不要使用 lambda
,而是使用 functools
模块中的 partial
函数:
# dummy function
def createFeature(df, i, col, name):
print(df)
print(i, col, name)
feature_functions = {
**{f'{col}{i}': partial(createFeature, i=i, col=col, name=f'{col}{i}')
for col, i in product(['New', 'Lost', 'Change'], list(range(1, 31)))}}
用法:
>>> feature_functions['New1'](pd.DataFrame)
Empty DataFrame
Columns: []
Index: []
1 New New1
>>> feature_functions['Lost23'](pd.DataFrame())
Empty DataFrame
Columns: []
Index: []
23 Lost Lost23
>>> feature_functions['Change12'](pd.DataFrame())
Empty DataFrame
Columns: []
Index: []
12 Change Change12
好的,这很有趣。如果你创建一个 returns 你的 lambda 的函数,例如:
def createFeatureCreator(i, col):
return lambda x: createFeature(df=x, i=i, col=col, name=f'{col}{i}')
并做你的理解(我删除了你的很多虚假内容):
feature_functions = {f'{col}{i}': createFeatureCreator(i, col)
for col, i in product(['New', 'Lost', 'Change'], range(1, 31))}
它如您所愿地工作。
“lambda”构造不能直接工作的原因实际上很有趣:lambda 捕获环境。字典理解是一个单一的环境,其中变量 i
和 col
在循环的每次迭代中都会发生变化。创建 lambda 时(实际上创建了 93 个不同的 lambda),它们都捕获相同的环境,因此当它们被执行时,i
和 col
的值是它们在环境(f 字符串扩展为函数调用,因为它在 lambda 内部而未执行,并且仅在您实际调用该函数时执行,这就是名称也显示为“错误”的原因)。