将项目附加到列表理解中的列表

Posted

技术标签:

【中文标题】将项目附加到列表理解中的列表【英文标题】:Appending item to lists within a list comprehension 【发布时间】:2011-01-31 02:56:46 【问题描述】:

我有一个列表,比如说a = [[1,2],[3,4],[5,6]]

我想将字符串'a' 添加到列表a 中的每个项目中。

当我使用时:

a = [x.append('a') for x in a] 

它返回[None,None,None]

但如果我使用:

a1 = [x.append('a') for x in a]

然后它做了一些奇怪的事情。

a,但不是a1[[1,2,'a'],[3,4,'a'],[5,6,'a']]

我不明白为什么第一个调用返回 [None, None, None],也不明白为什么第二个调用更改为 a 而不是 a1

【问题讨论】:

【参考方案1】:

对于第一种情况,它返回[None, None, None]的原因是因为list.append函数返回None,这就是它存储在列表中的内容。

第二种情况,是因为列表是可变的,每次追加值都会修改原来的列表。

您需要的是一个非就地附加运算符,例如+。即[x + ['a'] for x in a]

【讨论】:

【参考方案2】:

list.append 改变列表本身并返回None。列表推导式用于存储结果,如果您只想更改原始列表,则在这种情况下这不是您想要的。

>>> x = [[1, 2], [3, 4], [5, 6]]
>>> for sublist in x:
...     sublist.append('a')
...
>>> x
[[1, 2, 'a'], [3, 4, 'a'], [5, 6, 'a']]

【讨论】:

【参考方案3】:

(这是 Mike Graham 和 sykora 的答案的组合):

如果您只想就地更改值,请尝试常规 for 循环,而不是列表推导:

for sublist in a:
    sublist.append('a')

如果你想单独留下a,并将结果放在a1中:

a1 = [sublist + ['a'] for sublist in a]

正如他们解释的那样,append 修改了列表,但返回 None,而 + 不理会列表,但返回一个新的附加列表。

【讨论】:

那应该是 a1 = [sublist + ['a'] for sublist in a]。注意'a'周围的括号。【参考方案4】:

留下a = 并在a 上使用副作用:

[x.append('a') for x in a] 
print a

【讨论】:

请不要。仅仅为了利用它的副作用而丢弃列表理解是不好的形式;您的建议有效,但就像类似的 map 用法一样不受欢迎。显式优于隐式;使用循环而不是列表推导。【参考方案5】:

正如其他人所说,append 会改变列表本身,您不应该将其分配给变量。执行它会改变它的数据,有效地更新指向它的每个人。

但是,当我想以功能*的方式做一些事情时,我会使用一个技巧,同时改变现有对象(而不是构造新对象,在这种情况下使用 a=[x + ['a'] for x in a],或者特别是x + ['a'])。

所以,如果你足够勇敢,你也可以这样做:

>>> a=[[1,2],[3,4],[5,6]]
>>> a=[x.append('a') or x for x in a]
>>> a
[[1, 2, 'a'], [3, 4, 'a'], [5, 6, 'a']]

这是因为append 返回None,而or 继续搜索一个真值,x (它是一个list 与 at至少是附加到它的)。

我为什么需要这个?

假设您有一个列表,并且您想将其中的一些成员插入到一个新列表中,并相应地更新引用:

所以你有列表all

>>> all = [[], [], [], []]

其中一些被插入并更新到一个新列表x

>>> x = [i.append('x') or i for i in all[:2]]
>>> x
[['x'], ['x']]

all 的一部分也被插入并更新到列表y

>>> y = [i.append('y') or i for i in all[1:3]]

all 已更新:

>>> all
[['x'], ['x', 'y'], ['y'], []]

但是x也更新了:

>>> x
[['x'], ['x', 'y']]

并且y按预期生成:

>>> y
[['x', 'y'], ['y']]

总体而言,对于简单的任务,我建议使用for 循环显式更新。这就是pythonic。

从技术上讲,如果您可以访问列表类,则可以将其设为函数:

def more_functional_append(self, x):
    self.append(x)
    return self
functional programming 基于每条语句本质上只做一件事,并且没有副作用(因此,不会变异和返回)。 append 不是很实用,因为它会改变一个列表(纯函数式编程只有不可变对象)并且不返回结果以传递给其他操作(函数)。使用函数式编程概念,您可以创建没人能读懂的大型单行代码,也称为“工作安全”或“坏代码”。

【讨论】:

我现在对这个答案有不同的看法,所以如果你正在阅读这篇文章,请发表评论,以便我更新它。这里缺少函数式编程的核心特性,即不可变性,我应该对此进行扩展。 我很好奇你的新见解。 @Jan 我的新见解是,如果没有不变性,它就太复杂了。默认值应该是不可变的(并且 python 有一些解决方案,例如 frozensettuple) - 但它真的缺少没有 frozendict 并且没有不可变版本作为默认值。我真的不喜欢这个答案,因为它对 python 太陌生了。 当您也在就地更新内部列表时,使用列表推导来就地更新外部列表是非常奇怪的。使用该函数的代码可能会期望它就地或不就地,而不是两者的某种组合;这可能会导致难以追踪的错误。【参考方案6】:

您可以在列表推导中使用列表添加,如下所示:

a = [x + ['a'] for x in a] 

这给出了 a 的期望结果。在这种情况下,可以通过在循环之前将 ['a'] 分配给变量名来提高效率,但这取决于您想要做什么。

【讨论】:

【参考方案7】:

在您的列表理解的第一个值分配中,一个属性错误,“NoneType”对象没有属性“附加”,有助于解释为什么您的列表 a 将加载 None(s)。为了让我的控制台抛出错误,我使用 x 作为列表理解的变量以及迭代器。

Traceback (most recent call last):
x = [x.append('a') for x in a]
AttributeError: 'NoneType' object has no attribute 'append'

然后,我恢复为 a for x 并抛出了同样的错误。

Traceback (most recent call last):
a = [x.append('a') for x in a]
AttributeError: 'NoneType' object has no attribute 'append'

【讨论】:

以上是关于将项目附加到列表理解中的列表的主要内容,如果未能解决你的问题,请参考以下文章

将项目附加到列表列表中的指定列表(Python)[重复]

将单个项目附加到熊猫系列中的列表

将新项目附加到 Vue 2 中的列表

将列表中的索引附加到列表列表以创建 pandas df

使用Python中的多处理将项目附加到列表中

如何将列表项附加到数据框中的特定列?