使用循环中的变量在循环中生成函数会导致变量的阴影效应
generating functions in a loop using variables from the loop cause shadowing effects of variables
我想在循环中生成从循环中访问变量的小函数。然后我想一次组合并应用所有功能。 MWE 看起来是这样说的:
from functools import reduce
def compose(*funcs):
return lambda x: reduce(lambda y, f: f(y), reversed(funcs), x)
def replace_values_by_type(text, values, types) -> str:
def peek(x):
print('peek:', x)
return x
replacements = [lambda txt: peek(peek(txt).replace(peek(val), f'<{peek(typ)}>')) for val, typ in zip(values, types)]
replace = compose(*replacements)
text_with_replacements = replace(text)
print(values)
print(types)
print(text)
print(text_with_replacements)
print()
return text_with_replacements
replace_values_by_type('this is a test sentence', ['is', 'test'], ['A', 'B'])
当我 运行 我希望得到“this a sentence”。但是实际上只使用了循环中的最后一对 val
和 typ
。所以我猜会发生一些阴影或覆盖。你能解释一下吗?
-> % py mwe.py
peek: this is a test sentence
peek: test
peek: B
peek: this is a <B> sentence
peek: this is a <B> sentence
peek: test
peek: B
peek: this is a <B> sentence
['is', 'test']
['A', 'B']
this is a test sentence
this is a <B> sentence
顺便说一句。为了隔离问题,我还编写了这样的函数:
def replace_values_by_type(text, values, types) -> str:
replacements = []
for val, typ in zip(values, types):
def f(txt):
return txt.replace(val, f'<{typ}>')
replacements.append(f)
text_with_replacements = text
for f in replacements:
text_with_replacements = f(text_with_replacements)
return text_with_replacements
print(replace_values_by_type('this is a test sentence', ['is', 'test'], ['A', 'B']))
问题依旧。
列表理解创建的所有闭包都在同一个变量范围内,循环中只有一个 val
和 typ
变量实例。当稍后调用闭包时,变量具有上次迭代的值。
您需要为每次迭代在唯一范围内生成闭包。一种方法是编写一个单独的函数来 returns 闭包,因为每个函数都会建立一个新的范围。
def replacer(val, typ):
return lambda txt: peek(peek(txt).replace(peek(val), f'<{peek(typ)}>'))
replacements = [replacer(val, typ) for val, typ in zip(values, types)]
我想在循环中生成从循环中访问变量的小函数。然后我想一次组合并应用所有功能。 MWE 看起来是这样说的:
from functools import reduce
def compose(*funcs):
return lambda x: reduce(lambda y, f: f(y), reversed(funcs), x)
def replace_values_by_type(text, values, types) -> str:
def peek(x):
print('peek:', x)
return x
replacements = [lambda txt: peek(peek(txt).replace(peek(val), f'<{peek(typ)}>')) for val, typ in zip(values, types)]
replace = compose(*replacements)
text_with_replacements = replace(text)
print(values)
print(types)
print(text)
print(text_with_replacements)
print()
return text_with_replacements
replace_values_by_type('this is a test sentence', ['is', 'test'], ['A', 'B'])
当我 运行 我希望得到“this a sentence”。但是实际上只使用了循环中的最后一对 val
和 typ
。所以我猜会发生一些阴影或覆盖。你能解释一下吗?
-> % py mwe.py
peek: this is a test sentence
peek: test
peek: B
peek: this is a <B> sentence
peek: this is a <B> sentence
peek: test
peek: B
peek: this is a <B> sentence
['is', 'test']
['A', 'B']
this is a test sentence
this is a <B> sentence
顺便说一句。为了隔离问题,我还编写了这样的函数:
def replace_values_by_type(text, values, types) -> str:
replacements = []
for val, typ in zip(values, types):
def f(txt):
return txt.replace(val, f'<{typ}>')
replacements.append(f)
text_with_replacements = text
for f in replacements:
text_with_replacements = f(text_with_replacements)
return text_with_replacements
print(replace_values_by_type('this is a test sentence', ['is', 'test'], ['A', 'B']))
问题依旧。
列表理解创建的所有闭包都在同一个变量范围内,循环中只有一个 val
和 typ
变量实例。当稍后调用闭包时,变量具有上次迭代的值。
您需要为每次迭代在唯一范围内生成闭包。一种方法是编写一个单独的函数来 returns 闭包,因为每个函数都会建立一个新的范围。
def replacer(val, typ):
return lambda txt: peek(peek(txt).replace(peek(val), f'<{peek(typ)}>'))
replacements = [replacer(val, typ) for val, typ in zip(values, types)]