【问题标题】:Python lambda list: different behavior of list comprehension, for, and for in a functionPython lambda 列表:函数中列表理解、for 和 for 的不同行为
【发布时间】:2021-09-27 20:27:05
【问题描述】:

看看这段代码。我正在创建 3 个 lambda 函数列表(存储在变量 plus_n、plus_n_ 和 plus_n__ 中)。他们应该是完全一样的。但是,只有 plus_n_ 显示了预期的行为。

MAX=5
plus_n=[lambda x: x+i for i in range(MAX)]

plus_n_=[]
for i in range(MAX):
    plus_n_.append(lambda x: x+i)

def all_plus_n():
    plus_ns=[]
    for i in range(MAX):
        plus_ns.append(lambda x: x+i)
    return plus_ns
plus_n__=all_plus_n()    

for i in range(len(plus_n)):
    print('plus_n[{}]({})={}'.format(i,3,plus_n[i](3)))
    print('plus_n_[{}]({})={}'.format(i,3,plus_n_[i](3)))
    print('plus_n__[{}]({})={}'.format(i,3,plus_n__[i](3)))
    print()

输出:

plus_n[0](3)=7
plus_n_[0](3)=3
plus_n__[0](3)=7

plus_n[1](3)=7
plus_n_[1](3)=4
plus_n__[1](3)=7

plus_n[2](3)=7
plus_n_[2](3)=5
plus_n__[2](3)=7

plus_n[3](3)=7
plus_n_[3](3)=6
plus_n__[3](3)=7

plus_n[4](3)=7
plus_n_[4](3)=7
plus_n__[4](3)=7

看,如果是在函数上或在综合列表中,完全相同的代码会给出不同的结果...

那么,这 3 种方法之间有什么区别?怎么了? 如果我想在多个函数中使用这个变量,我必须将它用作全局变量吗?因为似乎我不能使用函数来获取变量值...

Tks 提前。

【问题讨论】:

标签: python list lambda


【解决方案1】:

这是the usual question 的一个有趣的变体。通常,plus_n_ 版本也不起作用,但您碰巧在代码末尾重用了i 作为测试的迭代变量。由于plus_n_ 捕获了全局i,并且测试循环还设置了全局i,因此从plus_n_ 检索到的lambda 每次通过循环都使用正确的值——即使它是 绑定i。列表理解有自己的作用域i,在评估后其值为4(之后不会改变);函数中的循环类似。


在 Python 中绑定函数参数的简洁、明确、简单的方法是标准库中的functools.partial

from functools import partial

MAX = 5

# Or we could use `operator.add`
def add(i, x):
    return i + x

# Works as expected, whatever happens to `i` later in any scope
plus_n = [partial(add, i) for i in range(MAX)]

这样,对partial 的每次调用都会生成一个可调用对象,该对象将自己的值绑定到 i,而不是后期绑定到名称 @987654337 @:

for j in plus_n:
    i = {"this isn't even a valid operand": 'lol'} # utterly irrelevant
    print(plus_n[j](3))

但是请注意,对于这种方法,要绑定的参数需要位于开头


解决具体示例问题的另一种方法是依赖绑定方法调用:

plus_n = [i.__add__ for i in range(MAX)]

你也可以hand-roll your own currying,但是为什么要重新发明轮子呢?


最后,可以使用 lambdas 的默认参数来绑定参数——尽管我非常不喜欢这种方法,因为它滥用the behaviour that causes another common problem 并暗示存在一个可以被覆盖但不是为它设计的参数:

plus_n = [lambda x, i=i: x+i for i in range(MAX)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多