【问题标题】:Unexpected result when changing list of functions (lambda) [duplicate]更改函数列表时出现意外结果(lambda)[重复]
【发布时间】:2021-03-06 03:41:30
【问题描述】:

我有一个函数列表,每个函数都有一个参数。

我想使用一个库的函数,它接受函数但希望它们没有参数。

所以我想创建一个新函数列表,使用 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循环)来查找根本原因,但没有成功。

我错过了什么?

【问题讨论】:

    标签: python lambda functools


    【解决方案1】:

    你可以使用 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

    大致来说,partial 会做这样的事情(除了关键字 args 支持等):

    def partial(func, *part_args):
        def wrapper(*extra_args):
            args = list(part_args)
            args.extend(extra_args)
            return func(*args)
    
        return wrapper
    

    【讨论】:

    • 它没有解释为什么问题中的例子不起作用?
    • 您能就@Jocker 的回答发表声明吗?我应该使用哪种解决方案,哪个更容易理解/更 Pythonic?
    • 对于这个用例,我发现functools.partiallambda 更容易理解,正如您发现的那样,要确定它有点棘手。当您阅读其他人的代码时尤其如此。在许多其他情况下,lambdas 非常好......但这只是我的意见,也许其他人会不同意。
    【解决方案2】:

    只需使用价值破解:

    funs_changed = [lambda f=f: f(0) for f in funs]
    

    没关系并产生以下输出:

    a
    b
    a
    b
    

    对于您的代码的初始变体还有一个解决方案:如果您希望将 do_something 函数保留为函数以避免主代码上下文中的内联 lamda-list 理解,只需修补 do_something 函数(我们将在函数中进行):

    def do_something(funs):
        funs_out = [lambda f=f: f(0) for f in funs]
        return funs_out
    

    【讨论】:

    • 但是为什么其他选项不起作用?
    • 你能详细说明你的答案吗?或者你能给我一些解释吗?我想了解您的解决方案/我的错误。
    • 是的。请在此处查找更多信息:docs.python.org/3.9/faq/…
    猜你喜欢
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多