Python闭包没有按预期工作

11 python lambda closures

当我运行以下脚本时,两个lambda都在同一个文件--junk.txt上运行os.startfile().我希望每个lambda使用值"f"设置为lambda创建时.有没有办法让它按照我的预期运作?

import os


def main():
    files = [r'C:\_local\test.txt', r'C:\_local\junk.txt']
    funcs = []
    for f in files:
        funcs.append(lambda: os.startfile(f))
    print funcs
    funcs[0]()
    funcs[1]()


if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

Joc*_*zel 22

一种方法是这样做:

def main():
    files = [r'C:\_local\test.txt', r'C:\_local\junk.txt']
    funcs = []
    for f in files:
        # create a new lambda and store the current `f` as default to `path`
        funcs.append(lambda path=f: os.stat(path))
    print funcs

    # calling the lambda without a parameter uses the default value
    funcs[0]() 
    funcs[1]()
Run Code Online (Sandbox Code Playgroud)

否则f在调用函数时会查找,因此您将获得当前(循环后)值.

我更喜欢的方式:

def make_statfunc(f):
    return lambda: os.stat(f)

for f in files:
    # pass the current f to another function
    funcs.append(make_statfunc(f))
Run Code Online (Sandbox Code Playgroud)

甚至(在python 2.5+中):

from functools import partial
for f in files:
    # create a partially applied function
    funcs.append(partial(os.stat, f))
Run Code Online (Sandbox Code Playgroud)

  • 这是有效的,因为默认参数在函数定义时绑定. (7认同)

650*_*502 5

重要的是要理解,当变量成为闭包的一部分时,它是变量本身,而不是被包含的值。

这意味着循环中创建的所有闭包都使用相同的变量f,该变量在循环结束时将包含循环内使用的最后一个值。

然而,由于语言的定义方式,这些捕获的变量在 Python 2.x 中是“只读”的:任何赋值都会使变量成为本地变量,除非声明它global(Python 3.x 添加了nonlocal关键字以允许写入外部作用域的本地变量) )。

正如 Jochen Ritzel 在他的回答中所说,避免这种变量捕获并获取值捕获的常见习惯用法是编写

lambda f=f: os.startfile(f)
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为默认参数值是在函数创建时评估的,并且f不是外部变量,而是一个函数参数,它将具有您想要的默认值(因此这个 lambda 只是一个具有参数默认值的函数,不会关闭任何词法不再有变量)。