在Python中定义函数列表

时间:2012-12-25 06:12:13

标签: python loops lambda

  

可能重复:
  Python lambdas and scoping

我希望以下内容能够生成3个常量函数的列表,取值为0,1和2:

lis = []
for i in range(3):
    lis.append( lambda: i )

但他们最终都获得了价值2.我希望深度复制可以解决这个问题,但似乎不起作用。

2 个答案:

答案 0 :(得分:3)

@Boud给出了一个非常好的答案,解释了为什么你的代码不能像你期望的那样工作。实际上,您必须在lambda中引用它之前评估i的值。这有点hacky方式:

lis = []
for i in range(3):
    lis.append( lambda i=i: i )

这使用Python的默认函数参数的值功能,例如在一个函数中,人们会写:

def f(i=10):
    return i

现在,诀窍是参数的默认值存储在创建函数(方法,lambda表达式)时。因此:

j = 10
def f(i=j):
    return i

j = 20
print( f(125) ) # no matter that j has been changed, the output is...
>>> 125

同样的技巧适用于lambda。为了使它更清晰:

lis = []
for j in range(3):
    lis.append( lambda i=j: i )

# Calling the lambdas
print(lis[1]())
>>> 1

答案 1 :(得分:1)

你循环避免写这样的东西:

lis.append( lambda: 0 )
lis.append( lambda: 1 )
lis.append( lambda: 2 )

您的目的是编写返回常量整数的lambda函数。但是您正在定义并附加一个返回对象i的函数。因此,附加的3个函数是相同的。

创建的函数后面的字节代码返回i

In [22]: import dis
In [25]: dis.dis(lis[0])
  3           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE        

In [26]: dis.dis(lis[1])
  3           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE        

In [27]: dis.dis(lis[2])
  3           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE   

调用这些函数中的任何一个都会在示例代码中返回i的最新值{/ 1}}:

2

如果删除In [28]: lis[0]() Out[28]: 2 对象,则会收到错误:

i

解决方案可能是继续使用循环来编写具有所需常量的代码并实际运行该代码:

In [29]: del i

In [30]: lis[0]()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-30-c9e334d64652> in <module>()
----> 1 lis[0]()

<ipython-input-18-15df6d11323a> in <lambda>()
      1 lis = []
      2 for i in range(3):
----> 3     lis.append( lambda: i )

NameError: global name 'i' is not defined

得到以下结果:

In [31]: lis = []
    ...: for i in range(3):
    ...:     exec 'lis.append( lambda: {} )'.format(i)
    ...: