【问题标题】:Python closures and cells (closed-over values)Python 闭包和单元格(封闭值)
【发布时间】:2012-02-08 08:14:07
【问题描述】:

是什么 Python 机制使它如此

[lambda: x for x in range(5)][2]()

是 4?

将 x 的副本绑定到每个 Lamba 表达式以使上述表达式等于 2 的常用技巧是什么?


我的最终解决方案:

for template, model in zip(model_templates, model_classes):
    def create_known_parameters(known_parms):
        return lambda self: [getattr(self, p.name)
                             for p in known_parms]
    model.known_parameters = create_known_parameters(template.known_parms)

【问题讨论】:

    标签: python lambda closures


    【解决方案1】:
    >>> [lambda x=x: x for x in range(5)][2]()
    2
    

    【讨论】:

    • 不错的答案。唯一的问题是“x”仍然可以被覆盖,因此它与零参数 lambda 并不完全相同。
    • @Neil True,尽管您没有在问题中指定它 必须 是零参数 lambda。如果您想允许其他参数,只需这样做:lambda a, b, x=x: a*x + b。我想不出可覆盖的 x 会成为问题的任何情况。
    • @NeilG,就其价值而言,我更喜欢这种方式;我比partial 或嵌套的lambda 语句更频繁地看到它;我发现它更具可读性。与lazyr 不同,我可以想到一些可覆盖的x 会成为问题的情况,但它们并不常见。 (懒惰,+1)
    • @senderle:我同意你的一次性代码。这种方法的问题在于,使用一个位置参数调用函数应该理想地引发TypeError。这样一来,它就会盲目地工作。对于库方法,这足以保证以另一种方式进行。和你一样,我发现嵌套的 lambda 很难阅读,所以我将外部 lambda 扩展为常规函数定义。 (请参阅我最近的编辑。)
    【解决方案2】:

    我一般用functools.partial:

    [ partial(lambda x: x, x) for x in range(5) ]
    

    当然,你也可以自己做:

    [ (lambda x: (lambda: x))(x) for x in range(5) ]
    

    【讨论】:

    • 是的,我选择了第二种解决方案,因为funtools.partial 在创建方法时效果不佳。
    【解决方案3】:

    由于没有人回答“机制是什么”部分,当我第一次阅读它时,这让我感到惊讶,这里是一个开始:

    这个:

    ls = [lambda: x for x in range(5)]
    

    有点像这样:

    ls = []
    x = 0
    ls.append(lambda: x)
    x = 1
    ls.append(lambda: x)
    x = 2
    ls.append(lambda: x)
    x = 3
    ls.append(lambda: x)
    x = 4
    ls.append(lambda: x)
    

    每个 lambda 都有自己的作用域,但这些作用域都不包含 x。所以他们都将通过查看外部范围来读取x 的值,所以当然他们都必须引用同一个对象。当它们中的任何一个被调用时,循环就完成了,并且该对象是整数4

    因此,即使这些 lambda 看起来像只包含不可变值的函数,它们仍然会受到副作用的影响,因为它们依赖于外部作用域中的绑定,并且该作用域可以改变。

    您当然可以通过重新绑定x 来进一步更改这些 lambdas 返回的内容,或者通过解除绑定来使它们抛出错误。但在列表解析版本中,x 仅绑定在列表解析内的私有范围内,因此您不能(很容易)弄乱它。

    解决方案当然是安排事情,使每个 lambda 在其本地范围内(或至少在 lambda 之间不共享的一些外部范围)中都有一个 x,以便它们都可以引用不同的对象。其他答案中已显示了执行此操作的方法。

    【讨论】:

      猜你喜欢
      • 2011-10-13
      • 1970-01-01
      • 2020-01-27
      • 1970-01-01
      • 1970-01-01
      • 2015-11-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      相关资源
      最近更新 更多