Python 如何使用循环创建一致的lambda函数?

Python 如何使用循环创建一致的lambda函数?,python,lambda,Python,Lambda,我想创建几个类似的lambda函数 当我使用一个简单的循环时,我没有得到我所期望的 代码: 输出: Before: 0 Before: 10 After: 10 10 After: 10 10 代码: 输出: Before: 0 Before: 10 After: 10 10 After: 10 10 如何使用I的“原始”值而不是I的最后一个已知值创建多个lambda函数?这是由于后期绑定 您已经创建了一个包含2个函数的列表 这些功能是什么乐趣(x):返回i*x 在这个阶

我想创建几个类似的lambda函数

当我使用一个简单的循环时,我没有得到我所期望的

代码:

输出:

Before:  0
Before:  10
After:  10 10
After:  10 10
代码:

输出:

Before:  0
Before:  10
After:  10 10
After:  10 10

如何使用
I
的“原始”值而不是
I
的最后一个已知值创建多个lambda函数?

这是由于后期绑定

  • 您已经创建了一个包含2个函数的列表
  • 这些功能是什么乐趣(x):返回i*x
  • 在这个阶段,python不关心i或x的值
  • 但循环结束时i的值是多少?”我应该是1岁
  • 调用
    funcList[0](10)
    时,它将返回i*x
  • 这里x是10,i是1,因此对
    funcList[0](10)
    的所有调用都将返回10

  • 注释
    f=lambda x,i=i:i*x
    中已经给出了答案,这将避免后期绑定,i的值将在创建函数对象时解析

    问题如下:Python中的闭包(请参阅)关闭其环境,将变量名映射到对象,它们通过将关闭的环境添加到其作用域查找链来实现这一点。考虑一个更简单、更明确的例子:

    import sys
    def foo():
        result = []
        for i in range(2):
            def bar():
                return i
            result.append(bar)
        return result
    
    foo
    的作用域查找链(在返回之前包含环境)类似于:

    - "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    def make_bar(j):
        def bar():
            return j
        return bar
    
    def foo():
        result = []
        for i in range(2):
            bar = make_bar(i)
            result.append(bar)
        return result
    
    funcList = []
    for i in range(2):
        def make_f(j):
            def f(x):
                return j * x
        funcList.append(make_f(i))
    
    也就是说,如果
    foo
    尝试使用变量
    z
    ,首先它会在第一个环境中查找(
    foo
    的局部变量)。如果存在,则查找成功。如果没有,它将移动到下一个(全局变量)。如果存在,则查找成功。如果没有,那么链上就没有更多的环境,因此会出现
    namererror

    在这种情况下,
    result
    i
    将被发现作为局部变量,
    foo
    sys
    也许其他变量将被发现作为全局变量,所有其他变量将给出一个
    namererror

    每个
    栏中的范围查找链类似于:

    - "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    def make_bar(j):
        def bar():
            return j
        return bar
    
    def foo():
        result = []
        for i in range(2):
            bar = make_bar(i)
            result.append(bar)
        return result
    
    funcList = []
    for i in range(2):
        def make_f(j):
            def f(x):
                return j * x
        funcList.append(make_f(i))
    
    最重要的是,
    foo
    的局部变量环境不会复制到
    bar
    的局部变量环境中。因此,
    bar
    可以查找
    i
    ,但是它首先在
    bar
    的局部变量中找不到它,然后在作用域链上找到一个,然后在
    foo
    的局部变量中找到它。因此,当定义第一个
    bar
    函数时,其范围查找链如下所示:

    - "bar" local variables: {}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {j: 0}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {j: 0}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    但是,当
    foo
    更改其局部变量
    i
    时,bar的范围查找链现在如下所示:

    - "bar" local variables: {}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {j: 0}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {j: 0}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    因此,现在当
    bar
    查找
    i
    时,它再次无法在其局部变量中找到它,在范围查找链中查找一个,并找到
    foo
    的局部变量
    i
    。。。现在是1,因为它与以前的
    i
    相同


    我在评论中写的诀窍有点老套。为了更明确一点,请考虑:

    def foo():
        result = []
        for i in range(2):
            def bar(j=i):
                return j
            result.append(bar)
        return result
    
    实际情况是,您正在使用参数
    j
    声明
    bar
    ,其默认值设置为
    i
    的值(即
    i
    在定义时引用的对象…而不是
    i
    在任何时候引用的对象
    j
    bar
    内部使用)。因此,第一个
    函数处的范围查找链如下所示:

    - "bar" local variables: {}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {j: 0}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {j: 0}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    当循环再次循环时,它看起来是这样的:

    - "bar" local variables: {}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {j: 0}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {j: 0}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    在这两种情况下,在
    bar
    的局部变量中查找
    j
    会立即成功,并且
    j
    不会改变


    执行以下操作有点麻烦,因为它只是隐藏了外部的
    i
    ,使它看起来像是在引用同一个
    i

    def foo():
        result = []
        for i in range(2):
            def bar(i=i):
                return i
            result.append(bar)
        return result
    
    但实际上,它们是两个不同的
    i
    s:

    - "bar" local variables: {i: 0}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    在循环的第二次迭代中:

    - "bar" local variables: {i: 0}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "make_bar" local variables: {j: 0}
    - "foo" local variables: {i: 1, result: [], bar: bar-function-2}
    - global variables: {make_bar: make_bar-function, foo: foo-function, sys: sys-module, etc...}
    

    可能更“恰当”的方法是做以下事情:

    - "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    def make_bar(j):
        def bar():
            return j
        return bar
    
    def foo():
        result = []
        for i in range(2):
            bar = make_bar(i)
            result.append(bar)
        return result
    
    funcList = []
    for i in range(2):
        def make_f(j):
            def f(x):
                return j * x
        funcList.append(make_f(i))
    
    在这种情况下,范围链是:

    - "bar" local variables: {}
    - "make_bar" local variables: {j: 0}
    - "foo" local variables: {i: 0, result: [], bar: bar-function-1}
    - global variables: {make_bar: make_bar-function, foo: foo-function, sys: sys-module, etc...}
    
    在循环的第二次迭代中:

    - "bar" local variables: {i: 0}
    - "foo" local variables: {i: 1, result: [bar-function-1], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "make_bar" local variables: {j: 0}
    - "foo" local variables: {i: 1, result: [], bar: bar-function-2}
    - global variables: {make_bar: make_bar-function, foo: foo-function, sys: sys-module, etc...}
    
    在这种情况下,它起作用是因为用
    i
    调用
    make\u bar
    ,调用
    make\u bar
    将其局部变量
    j
    设置为调用时
    i
    引用的对象(即
    0
    )<当
    foo
    i
    更改时,code>make_-bar
    的局部变量
    j
    不会更改


    在您的案例中,要做一个完全明确的示例,您可以做如下操作:

    - "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    - "bar" local variables: {}
    - "foo" local variables: {i: 1, result: [bar-function-1, bar-function-2], bar: bar-function-2}
    - global variables: {foo: foo-function, sys: sys-module, etc...}
    
    def make_bar(j):
        def bar():
            return j
        return bar
    
    def foo():
        result = []
        for i in range(2):
            bar = make_bar(i)
            result.append(bar)
        return result
    
    funcList = []
    for i in range(2):
        def make_f(j):
            def f(x):
                return j * x
        funcList.append(make_f(i))
    
    或者,作为:

    或者只是:

     funcList = [(lambda j: lambda x: j*x)(i) for i in range(2)]
    
    或者你也可以使用我提出的黑客,现在你已经知道了它的全部原理:

     funcList = [lambda x, i=i: i*x for i in range(2)]
    

    f=lambda x,i=i:i*x
    @Claudiu,真管用!但是为什么…?闭包魔术。通过这种方式,您可以强制lambda引入带有局部作用域的
    i
    ,而不是使用外部作用域的
    i
    @Felk:Claudiu的解决方案不是基于闭包的,它利用函数原型在定义时进行绑定,而函数体在调用时进行绑定。基于闭包的将是
    f=(lambda i:lambda x:i*x)(i)
    ;它的输入时间更长,稍微复杂一些,但与使用默认参数不同,它通过传递第二个参数消除了调用方更改
    i
    的风险。哦,你说得对,对不起