列表理解和函数返回多个值

时间:2013-09-29 19:05:27

标签: python list list-comprehension

我想使用列表推导来避免编写附加到某些列表的for循环。但它可以使用返回多个值的函数吗?我希望这个(简化示例)代码可以工作......

def calc(i):
    a = i * 2
    b = i ** 2
    return a, b

steps = [1,2,3,4,5]

ay, be = [calc(s) for s in steps]

......但它没有:(

附加到每个列表的for循环有效:

def calc(i):
    a = i * 2
    b = i ** 2
    return a, b

steps = [1,2,3,4,5]

ay, be = [],[]

for s in steps:
    a, b = calc(s)
    ay.append(a)
    be.append(b)

有没有更好的方法,还是我坚持这个?

3 个答案:

答案 0 :(得分:9)

zip*

一起使用
>>> ay, by = zip(*(calc(x) for x in steps))
>>> ay
(2, 4, 6, 8, 10)
>>> by
(1, 4, 9, 16, 25)

答案 1 :(得分:3)

返回迭代器的可怕的“节省空间”版本:

from itertools import tee

ay, by = [(r[i] for r in results) for i, results in enumerate(tee(map(calc, steps), 2))]

但基本上只是使用zip,因为大部分时间都不值得丑陋。


说明:

zip(*(calc(x) for x in steps))

(calc(x) for x in steps)获取[(2, 1), (4, 4), (6, 9), (8, 16), (10, 25)]迭代器

当你打开包装时,你会做相同的

zip((2, 1), (4, 4), (6, 9), (8, 16), (10, 25))

所以所有项目都会立即存储在内存中。证明:

def return_args(*args):
    return args

return_args(*(calc(x) for x in steps))
#>>> ((2, 1), (4, 4), (6, 9), (8, 16), (10, 25))

因此,所有项目都会立即存入内存。


那么我的工作如何?

map(calc, steps)(calc(x) for x in steps)(Python 3)相同。这是一个迭代器。在Python 2上,使用imap(calc(x) for x in steps)

tee(..., 2)获取两个迭代器,用于在迭代中存储差异。如果您以锁步方式迭代,tee将占用O(1)个内存。如果不这样做,tee最多可能会占用O(n)。所以现在我们的用法让我们可以获得O(1)内存。

enumerate显然会将其保持在恒定的记忆中。

(r[i] for r in results)返回一个迭代器,它从每个结果中获取i th 项。这意味着它在这种情况下会收到一对(依次为r=(2,1)r=(4,4)等)。它返回特定的迭代器。

因此,如果在锁步中迭代ayby,将使用常量内存。内存使用量与迭代器之间的距离成正比。这在很多情况下都很有用(想象一下文件或文件的差异),但正如我所说的那样,大多数时候它都不值得丑陋。还有一个额外的恒定因子开销。

答案 2 :(得分:2)

你应该告诉我们什么

[calc(s) for s in xrange(5)]

确实给了你,即

[(0, 0), (2, 1), (4, 4), (6, 9), (8, 16)]

虽然它不是您想要的2个列表,但它仍然是列表列表。此外,这看起来不一样吗?

zip((0, 2, 4, 6, 8), (0, 1, 4, 9, 16))

zip重新打包一组列表。通常它用2个较长的列表来说明,但它也适用于许多短列表。

第三步是记住fn(*[arg1,arg2, ...]) = fn(arg1,arg2, ...),即*解包列表。

把它们放在一起得到hcwhsa的答案。