【问题标题】: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

【问题讨论】:

    标签: python list append list-comprehension


    【解决方案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'
          

          【讨论】:

            猜你喜欢
            • 2011-10-12
            • 2019-11-06
            • 2020-03-29
            • 2011-05-15
            • 2017-09-20
            • 2021-08-01
            • 2013-12-24
            • 2013-03-08
            相关资源
            最近更新 更多