【问题标题】:How to capture a value for later in a nested function?如何在嵌套函数中捕获值以供以后使用?
【发布时间】:2020-09-23 07:10:48
【问题描述】:
def make_functions():
    flist = []

    for i in [1, 2, 3]:
        def print_i():
            print(i)
        flist.append(print_i)

    return flist

functions = make_functions()
for f in functions:
    f()

这段代码的输出是:

3
3
3

问题:

  1. 为什么print_i 只捕获i 的最终值?
  2. 我们如何修改此代码以使其打印1, 2, 3

回答问题 #2 的一种方法如下,但我想知道是否有更优雅的方法来捕获 i 的值。

def make_functions():
    flist = []

    for i in [1, 2, 3]:
        def print_i(j):
            print(j)
        flist.append((print_i, i))

    return flist

functions = make_functions()
for f, i in functions:
    f(i)

【问题讨论】:

    标签: python python-3.x function nested-function


    【解决方案1】:
    1. 就像上面的用户所说,在您的情况下,i 的范围是make_function。因此,当函数执行时,它们会在该范围内打印 i 的值 3。这是因为函数与 print(i) 的主体一起保存,而此时没有任何 i 的概念。 i 直到稍后调用该函数时才会计算,此时 i 已经是 3。

    2. 要回答问题 2,我们需要在 print_i 函数的范围内获取 i。我们可以使用以i 作为参数的包装函数来做到这一点,就像上面的用户所做的那样,或者更简单,我们可以将i 的值作为默认值传递。现在我们追加了 3 个不同的 print(i) 函数,每个函数都有自己的默认值,即 for 循环中此时 i 的值。

    def make_functions():
        flist = []
    
        for i in [1, 2, 3]:
            def print_i(i=i):
                print(i)
            flist.append(print_i)
    
        return flist
    
    functions = make_functions()
    for f in functions:
        f()
    

    【讨论】:

    • 这很聪明。我支持你,但接受了另一个答案,因为他也回答了我的问题 #1,而你没有回答。
    【解决方案2】:

    因为在你的例子中i的作用域是make_functions,你应该为它做一个单独的作用域,这里我把它包装成一个函数

    def make_functions():
        flist = []
    
        for i in [1, 2, 3]:
            def print_i_factory(i):
                def print_i():
                    print(i)
    
                return print_i
    
            flist.append(print_i_factory(i))
    
        return flist
    
    functions = make_functions()
    for f in functions:
        f()
    
    

    【讨论】:

    • 这是有道理的,但是如果i的范围是make_functions,代码如何打印i的最后一个值(问题1)?
    • @AbhijitSarkar 根据thisfor-loop makes assignments to the variables in the target list. This overwrites all previous assignments,因此问题 1 的 print_i 中的每个 i 都引用了该覆盖值
    • 嗯,这很好,但正如我在对另一个答案的评论中所说,imake_functions 中的一个局部变量,不应该在for 循环之后可用退出make_functions
    • @AbhijitSarkar this 可能会回答您的问题
    • 具体来说,“以前关于将 for 循环变量设置为循环本地的建议偶然发现了现有代码依赖循环变量在退出循环后保持其值的问题,并且它似乎这被认为是一个理想的功能”。我讨厌人们玩向后兼容卡,而开发人员则向后弯腰继续做明显错误的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    相关资源
    最近更新 更多