更改函数列表 (lambda) 时出现意外结果
Unexpected result when changing list of functions (lambda)
我有一个函数列表,每个函数都有一个参数。
我想使用一个库函数,它接受函数但期望它们没有参数。
所以我想创建一个新函数列表,使用 lambda 来“外部”传递参数
但是新的函数列表没有产生预期的结果。
(这是一些最小的例子)
def fun_a(param):
print("a")
def fun_b(param):
print("b")
def do_something(funs):
funs_out = []
for fun in funs:
funs_out.append(lambda: fun(0))
return funs_out
funs = [fun_a,fun_b]
funs[0](0) # prints a
funs[1](0) # prints b
funs_changed = do_something(funs)
#funs_changed = [lambda: f(0) for f in funs]
funs_changed[0]() # prints b ??? expected a
funs_changed[1]() # prints b
我之前尝试过 funs_changed = [lambda: f(0) for f in funs]
,因为它看起来更像 pythonic,然后尝试使用更明确的代码(原始 for 循环)来找到根本原因,但没有成功。
我错过了什么?
只需使用价值技巧:
funs_changed = [lambda f=f: f(0) for f in funs]
它可以并产生以下输出:
a
b
a
b
还有一个针对代码初始变体的解决方案:如果您希望将 do_something 函数保留为函数以避免在主代码上下文中进行内联 lamda-list 理解,只需修补函数即可(我们将在函数中执行):
def do_something(funs):
funs_out = [lambda f=f: f(0) for f in funs]
return funs_out
您可以使用 functools.partial:
from functools import partial
def fun_a(param):
print("a")
def fun_b(param):
print("b")
def do_something(funs):
funs_out = []
for fun in funs:
funs_out.append(partial(fun, 0))
return funs_out
funs = [fun_a, fun_b]
funs[0](0) # prints a
funs[1](0) # prints b
funs_changed = do_something(funs)
# funs_changed = [partial(fun, 0) for f in funs]
funs_changed[0]() # prints a
funs_changed[1]() # prints b
来自this answer:
Roughly, partial does something like this (apart from keyword args
support etc):
def partial(func, *part_args):
def wrapper(*extra_args):
args = list(part_args)
args.extend(extra_args)
return func(*args)
return wrapper
我有一个函数列表,每个函数都有一个参数。
我想使用一个库函数,它接受函数但期望它们没有参数。
所以我想创建一个新函数列表,使用 lambda 来“外部”传递参数
但是新的函数列表没有产生预期的结果。
(这是一些最小的例子)
def fun_a(param):
print("a")
def fun_b(param):
print("b")
def do_something(funs):
funs_out = []
for fun in funs:
funs_out.append(lambda: fun(0))
return funs_out
funs = [fun_a,fun_b]
funs[0](0) # prints a
funs[1](0) # prints b
funs_changed = do_something(funs)
#funs_changed = [lambda: f(0) for f in funs]
funs_changed[0]() # prints b ??? expected a
funs_changed[1]() # prints b
我之前尝试过 funs_changed = [lambda: f(0) for f in funs]
,因为它看起来更像 pythonic,然后尝试使用更明确的代码(原始 for 循环)来找到根本原因,但没有成功。
我错过了什么?
只需使用价值技巧:
funs_changed = [lambda f=f: f(0) for f in funs]
它可以并产生以下输出:
a
b
a
b
还有一个针对代码初始变体的解决方案:如果您希望将 do_something 函数保留为函数以避免在主代码上下文中进行内联 lamda-list 理解,只需修补函数即可(我们将在函数中执行):
def do_something(funs):
funs_out = [lambda f=f: f(0) for f in funs]
return funs_out
您可以使用 functools.partial:
from functools import partial
def fun_a(param):
print("a")
def fun_b(param):
print("b")
def do_something(funs):
funs_out = []
for fun in funs:
funs_out.append(partial(fun, 0))
return funs_out
funs = [fun_a, fun_b]
funs[0](0) # prints a
funs[1](0) # prints b
funs_changed = do_something(funs)
# funs_changed = [partial(fun, 0) for f in funs]
funs_changed[0]() # prints a
funs_changed[1]() # prints b
来自this answer:
Roughly, partial does something like this (apart from keyword args support etc):
def partial(func, *part_args): def wrapper(*extra_args): args = list(part_args) args.extend(extra_args) return func(*args) return wrapper