【问题标题】:When to drop list Comprehension and the Pythonic way?何时删除列表理解和 Pythonic 方式?
【发布时间】:2013-07-31 04:47:11
【问题描述】:

我创建了一行,通过以下方式将对象附加到列表中

>>> foo = list()
>>> def sum(a, b):
...      c = a+b; return c
...
>>> bar_list = [9,8,7,6,5,4,3,2,1,0]
>>> [foo.append(sum(i,x)) for i, x in enumerate(bar_list)]
[None, None, None, None, None, None, None, None, None, None]
>>> foo
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
>>>

线

[foo.append(sum(i,x)) for i, x in enumerate(bar_list)]

会给 pylint W1060 表达式分配任何内容,但是由于我已经在使用 foo 列表来附加值,因此我不需要将列表理解行附加到某些东西上。

我的问题更多是关于编程正确性的问题

我应该放弃列表理解并只使用简单的 for 表达式吗?

>>> for i, x in enumerate(bar_list):
...      foo.append(sum(i,x))

或者是否有正确的方法来使用列表理解和赋值?

回答

谢谢@user2387370、@kindall 和@Martijn Pieters。对于其余的 cmets,我使用 append 因为我没有使用 list(),我没有使用 i+x,因为这只是一个简化的示例。

我留下如下:

histogramsCtr = hist_impl.HistogramsContainer()
for index, tupl in enumerate(local_ranges_per_histogram_list):
    histogramsCtr.append(doSubHistogramData(index, tupl))
return histogramsCtr

【问题讨论】:

  • 我知道这只是一个例子,但为什么还要追加呢?为什么不只是foo = [sum(i, x) ...]
  • sum(i, x) 不起作用。你的意思是i + x
  • 如果你真的想要一个 1-liner,你可以在一行上放一个 for 循环。不过不推荐。

标签: python list-comprehension pylint code-complete


【解决方案1】:

是的,这是一种糟糕的风格。列表推导是建立一个列表。您正在构建一个充满Nones 的列表,然后将其丢弃。您实际期望的结果是这种努力的副作用。

为什么不首先使用列表推导来定义foo

foo = [sum(i,x) for i, x in enumerate(bar_list)]

如果它不是列表而是其他容器类,正如您在另一个答案的评论中提到的那样,编写该类以在其构造函数中接受一个可迭代对象(或者,如果它不是您的代码,则将其子类化所以),然后传递给它一个生成器表达式:

foo = MyContainer(sum(i, x) for i, x in enumerate(bar_list))

如果foo 已经有一些价值并且您希望追加新项目:

foo.extend(sum(i,x) for i, x in enumerate(bar_list))

如果您真的想要使用append(),并且出于某种原因不想使用for 循环,那么您可以使用这种构造;生成器表达式至少可以避免在您不想要的列表上浪费内存和 CPU 周期:

any(foo.append(sum(i, x)) for i, x in enumerate(bar_list))

但这比常规的for 循环要清晰得多,而且还有一些额外的工作要做:any 正在每次迭代中测试foo.append() 的返回值。您可以编写一个函数来使用迭代器并消除该检查;最快的方法是使用零长度collections.deque

from collections import deque
do = deque([], maxlen=0).extend

do(foo.append(sum(i, x)) for i, x in enumerate(bar_list))

这实际上是相当可读的,但我相信它实际上并不比any() 快,并且需要额外的导入。但是,do()any()for 循环快一点,如果这是一个问题的话。

【讨论】:

    【解决方案2】:

    我认为通常不赞成仅将列表推导用于副作用,所以我会说在这种情况下使用 for 循环更好。

    但无论如何,你不能只做foo = [sum(i,x) for i, x in enumerate(bar_list)]吗?

    【讨论】:

    • 我不能,因为在我的程序中 foo 是一个容器对象,append 方法做了一些其他的事情。
    • 然后要么只使用 for 循环,或者,如果容器对象属于您定义的类,则可以将 __init__ 更改为使用 *args 以便您可以执行 foo = MyContainerFoo(sum(i,x) for i, x in enumerate(bar_list))
    • 这不需要使用*args。生成器表达式是一个参数。
    • 对不起,我的意思是我更愿意定义它,以便它可以初始化为MyClass(1,2,3,4,5)(使用*args)或MyClass(*(i for i in range(1,6))),而不是MyClass([1,2,3,4,5])MyClass(i for i in range(1,6),但仅此而已只有我。
    【解决方案3】:

    您应该绝对删除列表理解。结束。

    • 您让阅读您的代码的人感到困惑。您正在建立一个副作用列表。
    • 您正在为构建一个您再次丢弃的列表支付 CPU 周期和内存。

    在您的简化案例中,您忽略了可以直接使用列表推导的事实:

    [sum(i,x) for i, x in enumerate(bar_list)]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-09
      • 2022-12-22
      • 2015-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-29
      相关资源
      最近更新 更多