【问题标题】:How can I use a function call result in a conditional list comprehension?如何在条件列表理解中使用函数调用结果?
【发布时间】:2016-03-15 05:22:11
【问题描述】:

我想把这段代码变成一个列表理解:

l = list()
for i in range(10):
    j = fun(i)
    if j:
        l.append(j)

意味着我只想将真实的fun() 结果值添加到列表中。如果没有对该函数调用的真实检查,列表理解将是:

l = [fun(i) for i in range(10)]

if fun(i) 添加到列表推导中会导致每次迭代对fun() 进行两次评估(实际上,并非总是如此!),因此如果fun() 不纯,则会导致意外的副作用。

我可以捕获fun(i) 的结果并在相同的理解中使用它,本质上是添加if j 吗? (相关问题here

【问题讨论】:

  • l = filter(None, map(fun, range(10)))l = [x for x in (fun(i) for i in range(10)) if x]
  • @falsetru:您的第一个语句返回一个可迭代的 filter 对象而不是一个列表,而您的第二个语句是一个 filter idiom 成语和一个实际列表。
  • 是的,您需要用list(...) 包裹第一个以获取列表。
  • @falsetru:这将导致总共两次迭代,除非所有 mapfilterlist 都懒惰地运行(按需)。
  • map, filter 在 Python 3.x 中惰性操作(返回迭代器)

标签: python-3.x list-comprehension


【解决方案1】:

您可以在列表 comp 中创建一个内部生成器,以便查看 func 的结果

l = [j for j in (func(i) for i in range(10)) if j]

【讨论】:

  • 这是filter idiom,但与返回可迭代filter 对象的惯用语不同,l 是请求的列表。
【解决方案2】:

或者结合两个建议的解决方案:

filter(None, (func(i) for i in range(10)))

【讨论】:

  • 这会返回一个filter object 可迭代对象,而不是一个列表本身。但在大多数情况下,这可能无关紧要。
【解决方案3】:

编辑

简单得多:

[res for res in map(func, range(10)) if res]

感谢 falstru 的提示。

旧答案

另一种选择是使用辅助生成器函数:

def call_iter(func, iterable):
    for arg in iterable:
        yield func(arg)

[res for res in call_iter(func, range(10)) if res]

【讨论】:

  • 虽然这可行,但它与我对单行代码的痴迷和争取最大代码密度的想法相矛盾 ;-)
  • 嗯,你可以重复使用这个函数。所以把它放到一个模块tools中,你只需要一个导入就可以得到你的单线。
  • 你不需要call_iter。你可以重复使用map
  • @falsetru 很明显。有时事情太简单以至于无法识别它们。固定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-23
  • 2017-03-10
  • 1970-01-01
  • 1970-01-01
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多