【问题标题】:Python Lambdas and Variable BindingsPython Lambda 和变量绑定
【发布时间】:2010-04-28 15:57:34
【问题描述】:

我一直在为自动化构建开发一个基本的测试框架。下面的一段代码代表了使用不同程序的两台机器之间的通信的简单测试。在我实际进行任何测试之前,我想完全定义它们 - 所以在声明所有测试之前,下面的这个测试实际上不会运行。这段代码只是一个测试的声明。

remoteTests = []
for client in clients:
    t = Test(
        name = 'Test ' + str(host) + ' => ' + str(client),
        cmds = [
            host.start(CMD1),
            client.start(CMD2),

            host.wait(5),

            host.stop(CMD1),
            client.stop(CMD2),
        ],
        passIf = lambda : client.returncode(CMD2) == 0
    )
remoteTests.append(t)

无论如何,在测试运行之后,它会运行 'passIf' 定义的函数。因为我想为多个客户端运行这个测试,所以我正在迭代它们并为每个客户端定义一个测试——没什么大不了的。但是,在第一个客户端上运行测试后,“passIf”会评估客户端列表中的最后一个,而不是 lambda 声明时的“客户端”。

然后我的问题是:python 什么时候在 lambdas 中绑定变量引用?我想如果使用 lambda 外部的变量是不合法的,解释器将不知道我在说什么。相反,它默默地绑定到最后一个“客户端”的实例。

另外,有没有办法按照我的意图强制解决?

【问题讨论】:

    标签: python


    【解决方案1】:

    client 变量是在外部范围内定义的,因此在运行 lambda 时,它将始终设置为列表中的最后一个客户端。

    要获得预期的结果,您可以为 lambda 提供一个具有默认值的参数:

    passIf = lambda client=client: client.returncode(CMD2) == 0
    

    由于在定义 lambda 时计算了默认值,因此其值将保持正确。

    另一种方法是在函数中创建 lambda:

    def createLambda(client):
        return lambda: client.returncode(CMD2) == 0
    #...
    passIf = createLambda(client)
    

    这里的 lambda 指的是 createLambda 函数中的 client 变量,它具有正确的值。

    【讨论】:

      【解决方案2】:

      发生的情况是您的 passIf 参数 lambda 引用了封闭范围内的 变量 client。它不是指变量client 在创建时所指的对象,而是变量本身。如果在循环结束后调用这些passIf,这意味着它们都引用循环中的最后一个值。 (在闭包术语中,Python 的闭包是后期绑定,而不是早期绑定。)

      幸运的是,将后期绑定闭包变成早期绑定闭包相当容易。您可以通过简单地为 lambda 提供一个参数来实现,默认值是您要绑定的值:

      passIf = lambda client=client: client.returncode(CMD2) == 0
      

      这确实意味着该函数会获得额外的参数,并且如果它被意外调用一个参数 - 或者当您希望该函数采用任意参数时,可能会搞砸。所以另一种技术是这样做:

      # Before your loop:
      def make_passIf(client):
          return lambda: client.returncode(CMD2) == 0
      
      # In the loop
      t = Test(
          ...
          passIf = make_passIf(client)
      )
      

      【讨论】:

      • 很好的解释。我觉得这让它更清楚一点:)。 “它不是指变量客户端在创建时引用的对象,而是变量本身。” 并且由于变量client是可变的,在循环结束时,它指向最后一个'client'对象。因此,该值仍然存在。
      猜你喜欢
      • 1970-01-01
      • 2015-12-28
      • 1970-01-01
      • 2012-02-17
      • 2021-10-13
      • 1970-01-01
      • 2011-02-07
      • 2010-12-13
      • 1970-01-01
      相关资源
      最近更新 更多