Python-Lambda函数的范围及其参数?

发布于 2021-02-02 23:15:07

我需要一个与一系列gui事件几乎完全相同的回调函数。该函数的行为会有所不同,具体取决于调用该事件的事件。对我来说,这似乎是一个简单的案例,但是我无法弄清楚lambda函数的这种奇怪行为。

因此,我在下面有以下简化代码:

def callback(msg):
    print msg

#creating a list of function handles with an iterator
funcList=[]
for m in ('do', 're', 'mi'):
    funcList.append(lambda: callback(m))
for f in funcList:
    f()

#create one at a time
funcList=[]
funcList.append(lambda: callback('do'))
funcList.append(lambda: callback('re'))
funcList.append(lambda: callback('mi'))
for f in funcList:
    f()

此代码的输出是:

mi
mi
mi
do
re
mi

我期望:

do
re
mi
do
re
mi

为什么使用迭代器搞砸了?

我试过使用Deepcopy:

import copy
funcList=[]
for m in ('do', 're', 'mi'):
    funcList.append(lambda: callback(copy.deepcopy(m)))
for f in funcList:
    f()

但这有同样的问题。

关注者
0
被浏览
58
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    这里的问题是m变量(参考)来自周围的范围。仅参数保留在lambda范围中。

    为了解决这个问题,你必须为lambda创建另一个范围:

    def callback(msg):
        print msg
    
    def callback_factory(m):
        return lambda: callback(m)
    
    funcList=[]
    for m in ('do', 're', 'mi'):
        funcList.append(callback_factory(m))
    for f in funcList:
        f()
    

    在上面的示例中,lambda还使用环绕范围来查找m,但是这次callback_factory是每次callback_factory 调用都创建一次的范围。

    或使用functools.partial:

    from functools import partial
    
    def callback(msg):
        print msg
    
    funcList=[partial(callback, m) for m in ('do', 're', 'mi')]
    for f in funcList:
        f()
    


  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    创建lambda时,它不会在其使用的范围内复制变量。它维护对环境的引用,以便以后可以查找变量的值。只有一个m。每次循环都会将其分配给它。循环后,变量m具有value 'mi'。因此,当你实际运行稍后创建的函数时,它将在创建该函数m的环境中查找的值,届时将具有value 'mi'

    解决此问题的一种常见且惯用的解决方案是,m通过使用lambda作为可选参数的默认参数来捕获创建lambda时的值。通常,你使用相同名称的参数,因此不必更改代码的主体:

    for m in ('do', 're', 'mi'):
        funcList.append(lambda m=m: callback(m))
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看