将项目附加到列表理解中的列表
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 有一些解决方案,例如frozenset
和 tuple
) - 但它真的缺少没有 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'
【讨论】:
以上是关于将项目附加到列表理解中的列表的主要内容,如果未能解决你的问题,请参考以下文章