在Python中可以在列表推导式中调用函数吗(非内置函数)?
假设我们有一个列表:
X = [1,2,3,4,5,6,7,8]
我们还创建了一个叫做 add() 的函数:
def add():
sum = 0
result = 0
for e in X:
sum = sum + e
return sum
add()
这个函数会遍历一个数字列表 X,把列表中的下一个元素加到之前的总和上。所以对于每个元素 X[i],我们有:
1
3
6
10
15
21
28
36
45
现在,如果我想把这些结果再放到一个列表里,利用列表推导式来实现。这种情况下,我能在列表推导式中调用像 add() 这样的函数吗?因为在列表推导式中使用内置函数是可以的。
我试过以下代码:
L = [add() for e in X]
print L
结果是
[None, None, None, None, None, None, None, None, None]
而我期望得到的是
[1,3,6,10,15,21,28,36,45]
为什么我在这个列表中得到的是 NoneType 的值呢?
5 个回答
是的,你可以在列表推导式中调用任何函数。
另外要注意,在Python 2.x版本中,你不能在列表推导式里使用print
,因为在那个版本里,print
并不是一个函数。
关于你的例子,它可以这样写,使用一个add()
函数,这个函数会和共享的状态(s
变量)一起工作:
s = 0 # better not use name 'sum' as it is already a builtin function
def add(i):
global s
s += i
return s
X = [1, 2, 3, 4, 5, 6, 7, 8]
print [add(i) for i in X]
# prints [1, 3, 6, 10, 15, 21, 28, 36]
# but beware the global shared state! for example when called again:
print [add(i) for i in X]
# prints [37, 39, 42, 46, 51, 57, 64, 72]
你可以看看其他的回答,了解如何在没有共享状态的情况下做到这一点,这样当你忘记把s = 0
时,就不会得到不同的结果。
#!/usr/bin/env python
"""
produce a list that adds each item to the previous item
this list [1,2,3,4] will produce this list [1,3,6,10]
"""
def accumulate(my_list, previous = 0):
for i in my_list:
previous += i
yield previous
x = [1,2,3,4,5,6,7,8,9]
new_list = []
new_list = [i for i in accumulate(x)]
print x
print new_list
这段代码会产生这样的结果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 3, 6, 10, 15, 21, 28, 36, 45]
你的方法行不通,因为你的 add()
函数没有状态。你需要一个能够在多次调用 add()
之间保持状态的东西,否则 add()
每次都会产生相同的结果。
实现你想要的一个解决方案是 itertools.accumulate()
。你可以查看 在Python中等同于Haskell的scanl 的讨论。
这里其他的回答建议使用一个包含 range()
的列表推导式。虽然这样可以实现,但效率不高,因为它是一个O(n^2)的算法,每次都要从头计算累积和。
是的,在列表推导式里面调用函数是可以的。你给的例子没问题,问题出在 add()
这个函数上。你需要让 add()
函数接收一个参数,也就是要计算总和的列表。
def add(elements):
sum = 0
for el in elements:
sum += el
return sum
这样,列表推导式就会变成这样:
L = [add(X[:i+1]) for i in xrange(len(X))]
[1, 3, 6, 10, 15, 21, 28, 36]
这和下面的写法是一样的:
L = [add(X[:1]), add(X[:2]), ..., add(X[:8])]
结果会是一个前缀和的列表,也就是你想要的东西。
你可以使用 yield
这个关键词,来保持你原来的格式:
X = [1,2,3,4,5,6,7,8]
def add():
sum = 0
for e in X:
sum = sum + e
yield sum
L = [value for value in add()]
print L