我在使用lambdas语法时遇到了问题,我试图将一个booleans列表翻译成一个整数值,但我得到了一个错误,我不明白为什么。
下面是代码。
from functools import reduce
binary = [True, True, False, True]
L = list(range(len(binary))) #Step 1
print(L) #[0, 1, 2, 3]
L = map(lambda a: 2**a, L) #Step 2
print(L) #[1, 2, 4, 8]
L = zip(binary, L) #Step 3
print(L) #[(True, 1),(True, 2),(False, 4),(True, 8)]
L = filter(lambda a, b: a, L) #Step 4
print(L) #[(True, 1),(True, 2),(True, 8)] not sure
L = map(lambda a, b: b, L) #Step 5
print(L) #?????
L = reduce(lambda a, b: a + b, L) #Final step
print(L) #11
输出:
Traceback (most recent call last):
File "C:/Users/axel_/PycharmProjects/Python_Subject_Exam/19_new_exam_binary_list_translation.py", line 27, in <module>
L = reduce(lambda a, b: a + b, L)
TypeError: <lambda>() missing 1 required positional argument: 'b'
[0, 1, 2, 3]
<map object at 0x00000267FAFE5388>
<zip object at 0x00000267FAFE50C8>
<filter object at 0x00000267FAFE5248>
<map object at 0x00000267FAFE4EC8>
Process finished with exit code 1
谁能帮我调试一下?
我想这可以解决你的问题。我将在代码中写一些注释来帮助你理解。
from functools import reduce
binary = [True, True, False, True]
L = list(range(len(binary))) #[0, 1, 2, 3]
L = map(lambda a: 2**a, L) #[1, 2, 4, 8]
L = zip(binary, L) #[(True, 1), (True, 2), (False, 4), (True, 8)]
L = filter(lambda x: x[0], L) #<--- an item from zip() is an ((unpacked)) tuple
L = map(lambda x: x[1], L)
L = reduce(lambda a, b: a + b, L)
print(L) #11
如果你是新手,这是对迭代器的挑战之一。
迭代器是在每个项目被拉下迭代器时被评估的,这意味着当你调用reduce来组合结果时,所有的lambda表达式都在那个时候被评估。你的例子这相当于下面的表达式。
L = list(range(len(binary)))
L = reduce(lambda a, b: a + b,
map(lambda a, b: b,
filter(lambda a, b: a,
zip(binary,
map(lambda a: 2**a, L)
)
)
)
)
print(L)
令人困惑吗?
在你的例子中,这一行 L = filter(lambda a, b: a, L) #Step 4
有一个错误。过滤器表达式将一个可调用的表达式,该表达式将一个 单一 参数以及一个可迭代参数,但由于它没有被评估到最后,你会得到一个混乱的错误。
一种方法(也是调试时的好方法)是将每一步都包在一个调用列表中,以迫使评估发生在每一行,例如 L = list(filter(lambda a, b: a, L))
. 这将使错误的位置更加明显。
或者使用生成器表达式而不是 filter
map
eg:
# filter (return odd numbers between 1 and 10)
result_a = filter(lambda a: a % 2, range(1, 11))
result b = (a for a in range(1, 11) if a % 2)
# map (return powers of 2)
result_a = map(lambda a: 2**a, range(11))
result_b = (2**a for a in range(11))
所有的结果都是一样的 但生成器表达式有另一个技巧 你可以使用元组解包,这样就可以了。
result = (b for a, b in zip(binary, range(len(binary))) if a)
此外,python还有其他的内置功能,可以进一步简化代码。
Enumerate 将返回一个计数器,加上迭代器中的每个元素,使得前三步可以简化为。
# 1 step 1, 2 and 3 can be simplified with enumerate
L = ((i**2, b) for i, b in enumerate(L))
接下来可以用sum代替reduce,sum将迭代表中的所有数值加在一起。
L = reduce(lambda a, b: a + b, L)
# is equivalent to
L = sum(L)
然后把所有的数值加在一起 整个序列就可以简化为:
L = sum(2**i for i, b in enumerate(binary) if b)
希望能帮到你