嵌套/多列表推导或生成器表达式的用例。什么时候更优雅?

时间:2009-03-15 22:22:52

标签: python list-comprehension generator-expression

我有时会看到这种事:

(k for k in (j for j in (i for i in xrange(10))))

现在这真的让我的大脑弯曲,我宁愿不以这种方式呈现。

是否有任何用例,或使用过这些嵌套表达式的例子,它比嵌套循环更优雅,更易读?

编辑:感谢您提供简化此方法的示例。实际上并不是我要求的,我想知道是否有任何优雅的时刻。

7 个答案:

答案 0 :(得分:19)

检查PEP 202,这是语言中引入了列表推导语法的地方。

为了理解你的例子,Guido本人有一个简单的规则:

  • 形式[... for x ... for y ...]嵌套,最后一个索引   变化最快,就像嵌套for循环一样。

同样来自PEP 202,用于回答您的问题:

Rationale
    List comprehensions provide a more concise way to create lists in
    situations where map() and filter() and/or nested loops would
    currently be used.

如果你遇到这样的情况,你会发现它更优雅。但是,恕我直言,您的代码中的多个嵌套列表推导可能不如嵌套for循环,因为for循环很容易在视觉上解析。

答案 1 :(得分:14)

如果您担心某一行的复杂程度过高,可以将其拆分:

(k for k in 
    (j for j in 
        (i for i in xrange(10))))

我总是发现线条延续在Python中看起来有些奇怪,但这确实可以更容易地看到每个循环的内容。由于额外的赋值/查找不会产生或破坏任何东西,你也可以这样写:

gen1 = (i for i in xrange(10))
gen2 = (j for j in gen1)
gen3 = (k for k in gen2)

在实践中,我认为我没有嵌套超过2深的理解,在那时它仍然很容易理解。

答案 2 :(得分:5)

就你的例子而言,我可能会把它写成:

foos = (i for i in xrange(10))
bars = (j for j in foos)
bazs = (k for k in bars)

鉴于更具描述性的名称,我认为这可能非常清楚,我无法想象会有任何可测量的性能差异。

也许你正在考虑更多的表达方式:

(x for x in xs for xs in ys for ys in lst)

- 实际上,这甚至都没有效。你必须按其他顺序放置东西:

(x for ys in lst for xs in ys for x in xs)

我可能会把它写成一个简化列表的快速方法,但总的来说我认为你写的是:通过输入less来节省的时间通常会与你花费额外的时间来平衡生成器表达式。

答案 3 :(得分:4)

由于它们是生成器表达式,因此您可以将每个绑定到它自己的名称,以使其更具可读性,而不会改变性能。将其更改为嵌套循环可能会对性能产生不利影响。

irange = (i for i in xrange(10))
jrange = (j for j in irange)
krange = (k for k in jrange)

你选择哪个并不重要,我认为多行示例通常更具可读性。

答案 4 :(得分:1)

警告:优雅部分是品味问题。

列表推导永远不会比相应的扩展for循环更清楚清除。 For循环也比列表推导更强大强大。那么为什么要使用它们呢?

列表理解是简洁 - 它们允许您在一行中执行某些操作。

使用列表推导的时间是当你需要某个列表时,它可以很容易地在飞行中创建,并且你不需要或者不需要中间对象。当您需要将当前作用域中的某些对象打包到可以提供给函数的单个对象中时,可能会发生这种情况,如下所示:

list1 = ['foo', 'bar']
list2 = ['-ness', '-ity']
return filterRealWords([str1+str2 for str1 in list1 for str2 in list2])

此代码与扩展版本相比具有可读性,但它更短。它避免了创建/命名仅在当前范围内使用过一次的对象,这可以说是更优雅。

答案 5 :(得分:0)

表达式:

(k for k in (j for j in (i for i in xrange(10))))

相当于:

(i for i in xrange(10))

几乎相同:

xrange(10)

最后一个变体比第一个更优雅。

答案 6 :(得分:0)

我觉得在这样的情况下它可以是有用和优雅的,你有这样的代码:

output = []
for item in list:
    if item >= 1:
        new = item += 1
        output.append(new)

你可以像这样做一个单行:

output = [item += 1 for item in list if item >= 1]