リストのPythonのappend()と+演算子、なぜこれらの結果が異なるのですか?


113

なぜ、これらの2つの操作が(んappend()RESP。 +)異なる結果を与えますか?

>>> c = [1, 2, 3]
>>> c
[1, 2, 3]
>>> c += c
>>> c
[1, 2, 3, 1, 2, 3]
>>> c = [1, 2, 3]
>>> c.append(c)
>>> c
[1, 2, 3, [...]]
>>> 

最後のケースでは、実際には無限の再帰があります。c[-1]c同じです。どうして+手術と違うの?


1
実行可能な新しい質問に対するすべての敬意をもって:私は元の質問にロールバックしてそれをきれいに保ちました(スレッドごとに1つの質問、SO FAQを参照)。新しい質問をするか、各回答の下のコメントスレッド内でフォローアップの質問をしてください。注:編集内容は失われません。履歴をクリックすると、それをコピーして新しい質問に貼り付けることができます。
Abel


それは異なるansを与えるようですが、そのようではありません。+演算子を使用して値を追加する場合は、[]記号を使用します。c + = [c]は、appendと同じ結果になります。
Sharif Chowdhury 2017

@SharifChowdhury同じ結果が得られると思います
トラストリー

回答:


142

「なぜ」を説明するには:

この+操作により、配列要素が元の配列に追加されます。このarray.append操作は、配列(または任意のオブジェクト)を元の配列の最後に挿入します。これにより、その場所にある自己へ参照が発生します(したがって、無限再帰)。

ここでの違いは、要素を連結することにより、配列を追加すると+操作が特定の動作をすることです(他の配列と同様にオーバーロードされます。この章を参照してください)。ただし、append-methodは文字通り、ユーザーが要求することを実行します。要素を取得する代わりに、指定した右側のオブジェクト(配列またはその他のオブジェクト)を追加します。

代替

extend()+演算子と同様に機能する関数を使用する場合に使用します(他の人もここで示したように)。反対のことをするのは賢明ではありません。リストの+演算子を使用して追加を模倣しようとすることです(理由については、以前のリンクを参照してください)。

小さな歴史

おもしろい、少し歴史:1993年2月にPython配列モジュールが誕生したことは驚くかもしれませんが、配列は配列とリストが登場した後に追加されました。


2
+1は常に正確な情報を支持しているためです。公式ドキュメントへのリンクは常にプラスです。
ジェサニズム

10
「なぜ」の別の部分:正気の人々は+対称的であると期待しています:リストとリストを連結します。
Beni Cherniavsky-Paskin、2010年

1
+1、良い点ベニ(「rh側のオブジェクトはlh側の配列に追加される」と言っても「正気」と見なすことができますが、個人的には現在の動作の方が理にかなっていると思います)。
Abel

要素が単一の文字列である場合(例:s = 'word'、l = ['this'、 'is'])。その場合、l.append(s)とl + sは同じでなければなりません。私は正しいですか?
user3512680

23

連結演算子+は、リストに適用されると、2つのオペランドのそれぞれのすべての要素を含む新しいリストを返す2項中置演算子です。list.append()この方法は、mutatorlistの単一追加object(特定の例リスト内の引数をc対象とします)list。あなたの例では、これはcそれ自体への参照を追加することになります(したがって、無限再帰)。

「+」連結の代替

このlist.extend()メソッドは、sequence引数を主語と連結するミューテーターメソッドでもありlistます。具体的には、の各要素をsequence反復順に追加します。

余談

演算子で+あるため、式の結果を新しい値として返します。非連鎖mutatorメソッドであるlist.extend()ため、件名リストをインプレースで変更し、何も返しません。

配列

これは、上記のAbelの回答がリスト、シーケンス、および配列の議論を混合することによって引き起こす可能性のある混乱の可能性があるため、追加しました。 Arrays整数データ型の配列を格納するより効率的な方法として、シーケンスとリストの後にPythonに追加されました。混同しないようにしてくださいarrayslists。彼らは同じではありません。

配列ドキュメントから:

配列はシーケンス型であり、配列に格納されているオブジェクトのタイプが制限されていることを除いて、リストとほとんど同じように動作します。タイプは、オブジェクト作成時にタイプコード(単一の文字)を使用して指定されます。


18

append要素をリストに追加しています。リストを新しいリストで拡張する場合は、使用する必要がありますextend

>>> c = [1, 2, 3]
>>> c.extend(c)
>>> c
[1, 2, 3, 1, 2, 3]

4
操作が同じではないため、結果が異なる理由は明らかと思いました。もしそれが現れて+extend私たちが何か考えるべき異なる結果を生み出すとしたら。
SilentGhost 2010年

1
1:私は「なぜ」の質問を嫌う理由:append+異なっています。それが理由です。私はこの答えが好きです。なぜなら、それがより理にかなったことを行うからです。
S.Lott

このサイトは尋ねられた質問に答えることについてではありませんか?なぜPHPがPHPと呼ばれるのか、なぜ__lt__Pythonでオーバーロードできないのか(最近は可能)と人々は尋ねます。なぜ質問は最も重要な質問ですが、多くの場合、答えるのが最も難しいです。彼らは、マニュアルへのポインタではなく、本質を求めます。そしてもちろん、質問が嫌いな場合(私はほとんど嫌いです)は答えないでください;-)
Abel

さらにデモでは、多分示したc += [c]c.append(c[:])あまりにも。
10

2
@アベル:なぜa+b != a*bですか?これらは異なる操作です。それが答えです。「なぜ」は、「適切に追加するにはどうすればよいですか?」など、他の質問ほど役に立ちません。または「無限再帰につながるこの追加の何が問題になっていますか?」「Xをどうするか」または「Xを実行したときに何が問題になったか」という質問 または、「Xの代わりに何をすべきか」は、誰かが学ぶのにも役立ちますが、焦点が絞られ、使いやすく、実用的な答えを提供します。
S.Lott

8

Pythonリストは異種混合です。つまり、同じリスト内の要素はどのタイプのオブジェクトでもかまいません。式:c.append(c)オブジェクトをcリストに追加します。この場合、リスト自体がリストのメンバーになります。

c += cは2つのリストを一緒に追加し、結果を変数に割り当てますc。オーバーロード+された演算子はリストで定義され、最初のリストの要素と2番目のリストの要素を内容とする新しいリストを作成します。

したがって、これらは実際には、設計によって異なることを実行するために使用される異なる表現です。


7

あなたが探している方法はですextend()。Pythonのドキュメントから:

list.append(x)
    Add an item to the end of the list; equivalent to a[len(a):] = [x].

list.extend(L)
    Extend the list by appending all the items in the given list; equivalent to a[len(a):] = L.

list.insert(i, x)
    Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).


2

ドキュメントを参照してください:

list.append(x)

  • リストの最後にアイテムを追加します。a [len(a):] = [x]と同等です。

list.extend(L)-指定されたリスト内のすべてのアイテムを追加してリストを拡張します。a [len(a):] = Lと同等です。

c.append(c)cを要素としてそれ自体に「付加」します。リストは参照型であるため、これは再帰的なデータ構造を作成します。

c += ccの要素をcextend(c)追加すると同等です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.