web-dev-qa-db-ja.com

リスト内包内のリストへのアイテムの追加

リストがあります、たとえば、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]が返される理由も、2番目の呼び出しがa1ではなくaで変更される理由もわかりません。

25
ariel

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']]
35
Mike Graham

他の人が言ったように、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']]

これは、appendNoneを返し、orxである真理値の値を探し続けるため、機能します。 is(これは、少なくとも追加されたlistです)。

なぜこれが必要なのですか?

リストがあり、そのメンバーの一部を新しいリストに挿入し、それに応じて参照を更新するとします。

だからあなたはリスト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
  • 関数型プログラミング は、すべてのステートメントが基本的に1つのことを行い、副作用がない(つまり、変更や復帰を行わない)ことに基づいています。 appendは、リストを変更し(純粋な関数型プログラミングは不変オブジェクトのみを持つ)、他のアクション(関数)に渡す結果を返さないため、あまり機能的ではありません。関数型プログラミングの概念を使用すると、「ジョブセキュリティ」または「不良コード」としても知られる、誰も読めない大きな大きな1行を作成できます。
16
Reut Sharabani

最初のケースでは、[None, None, None]Noneを返すため、list.appendが返されます。これがリストに格納されているものです。

2番目のケースでは、リストが変更可能であり、値を追加するたびに元のリストが変更されます。

必要なのは、+などの非インプレース追加演算子です。つまり、[x + ['a'] for x in a]です。

11
sykora

(これはMike Grahamとsykoraによる回答の組み合わせです):

値をインプレースで変更するだけの場合は、リスト内包ではなく、通常のforループを試してください。

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

あなたが一人のままにして、結果をa1に入れたい場合:

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

彼らが説明したように、appendはリストを変更しますが、Noneを返しますが、+はリストをそのままにしますが、新しく追加されたリストを返します。

4
Oddthinking

次のように、リスト内包内でリスト追加を使用できます。

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

これにより、aに望ましい結果が得られます。この場合、ループの前に変数名に['a']を割り当てることでより効率的にすることができますが、それは何をしたいかによって異なります。

2
Bud

出て a =aの副作用を使用:

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

リスト内包の最初の値の割り当てで属性エラー、「NoneType」オブジェクトに属性「append」がないため、リストaにNone(s)がロードされる理由を説明できます。コンソールでエラーをスローするために、リスト内包表記の変数として、また反復子としてxを使用しました。

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

次に、xのaに戻したところ、同じエラーが発生しました。

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