2009-12-03 75 views
25

如果我做的功能两个列表lambda表达式:生成函数与蟒蛇

def makeFun(i): 
    return lambda: i 

a = [makeFun(i) for i in range(10)] 
b = [lambda: i for i in range(10)] 

为什么名单ab不相等?

例如:

>>> a[2]() 
2 
>>> b[2]() 
9 

回答

18

技术上,lambda表达式是关闭i,在全球范围内,这是最后一组到9的可见这是相同i被所有10个lambda表达。例如,

i = 13 
print b[3]() 

makeFun功能,拉姆达上i关闭被调用该函数时的已定义。那十个不同i s。

+0

好吧,现在这对我来说很合理。谢谢! – Anssi 2009-12-03 17:15:16

1

lambda表达式在Python份额他们所创建的变量的作用域在你的第一种情况,拉姆达的范围makeFun的。在第二种情况下,它是全球性的i,它是9,因为它是循环中的剩余物。

这就是我理解的也无妨......

1

好的。列表理解中的lambda每次都会看到相同的本地i

你可以把它改写为:

a = [] 
for i in range(10): 
    a.append(makefun(i)) 

b = [] 
for i in range(10): 
    b.append(lambda: i) 

具有相同的结果。

+0

我不确定你想说什么。在你的例子中,'b [2]()'也返回9. – 2009-12-03 17:06:52

+0

我说它相当于列表解析。不是说a和b是一样的。 我觉得拼写出来的'for'循环会让我们更容易看到'i'从哪里来。 – 2009-12-03 17:31:54

7

一组函数(a)中传递的参数和其他的(b)中运行在一个全局变量,然后将其设置为9.检查拆卸操作:

>>> import dis 
>>> dis.dis(a[2]) 
    1   0 LOAD_DEREF    0 (i) 
       3 RETURN_VALUE 
>>> dis.dis(b[2]) 
    1   0 LOAD_GLOBAL    0 (i) 
       3 RETURN_VALUE 
>>> 
18

正如其他人指出,范围是问题。请注意,您可以通过添加额外的参数lambda表达式,并分配给它的默认值解决这个问题:

>> def makeFun(i): return lambda: i 
... 
>>> a = [makeFun(i) for i in range(10)] 
>>> b = [lambda: i for i in range(10)] 
>>> c = [lambda i=i: i for i in range(10)] # <-- Observe the use of i=i 
>>> a[2](), b[2](), c[2]() 
(2, 9, 2) 

结果是i现在明确地放在局限于lambda表达范围。

3

要添加一些清晰度(至少在我的脑海里)

def makeFun(i): return lambda: i 
a = [makeFun(i) for i in range(10)] 
b = [lambda: i for i in range(10)] 

一个使用makeFun(我),这是自变量的函数。

b使用lambda:i,这是一个函数而不是参数。它使用的我是从以前的

非常不同,以使a和b等于我们可以做出两种功能使用不带参数:

def makeFun(): return lambda: i 
a = [makeFun() for i in range(10)] 
b = [lambda: i for i in range(10)] 

现在,这两个功能使用全局我

>>> a[2]() 
9 
>>> b[2]() 
9 
>>> i=13 
>>> a[2]() 
13 
>>> b[2]() 
13 

或(更有用)使两个使用一个参数:

def makeFun(x): return lambda: x 
a = [makeFun(i) for i in range(10)] 
b = [lambda x=i: x for i in range(10)] 

我故意改变我与x其中变量是本地的。 现在:

>>> a[2]() 
2 
>>> b[2]() 
2 

成功!