いきなりですが問題です.Pythonで書かれた,以下のプログラムコードをご覧ください.
a = (1, 2, 3) b = a c = [1, 2, 3] d = c print(a, b, c, d) a = a + (4,) c.append(4) print(a, b, c, d) a += (5,) c += [5] print(a, b, c, d) a = a + (6,) c = c + [6] print(a, b, c, d)
最初にprint関数を呼び出したときの出力は,次の通りです.
(1, 2, 3) (1, 2, 3) [1, 2, 3] [1, 2, 3]
このときの,変数aからdまでの状況を最も適切に表したのは,以下の3つの画像のどれでしょうか.
さっそくですが解答です.最も適切に表したのは,以下の画像です.
aとbは,出力により(1, 2, 3)となるタプルを参照し,cとdは,[1, 2, 3]となるリストを参照しています.タプルとリストの違いは,例えば以下より読むことができます.
冒頭のプログラムでは,「print(a, b, c, d)」が4回実行されます.そのたびに,4つの変数が参照する内容(データ構造)を出力します.2回目の呼び出しの出力は,次のようになります.
(1, 2, 3, 4) (1, 2, 3) [1, 2, 3, 4] [1, 2, 3, 4]
ここから,タプルとリストの違いを知ることができます.まず,1回目と2回目のprint関数の呼び出しの間に書かれた「a = a + (4,)」を実行することで,aとbとで参照するタプルが変わります.aは,新たに作られたタプル(1, 2, 3, 4)を参照することになるのに対し,bは変わりません.
リストについては,「c.append(4)」を実行することで,cが参照するリストの末尾に4が追加され,出力としては[1, 2, 3, 4]となります.要素が増えたこのリストを,cも,dも,参照しています.リストの状態は変わるけれども,その参照は変わらない,ということです.
図は次の通りとなります.
3回目の呼び出しの出力は,次のようになります.
(1, 2, 3, 4, 5) (1, 2, 3) [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
タプルへの値の追加は,2回目の前のときと同様です*1.リストへの値の追加は,「c += [5]」に変わりましたが,要素数が5になり,cも,dもこのリストを参照しているのは,変わりません.図は次の通りです.
最後の呼び出しの出力には,少し注意が必要です.
(1, 2, 3, 4, 5, 6) (1, 2, 3) [1, 2, 3, 4, 5, 6] [1, 2, 3, 4, 5]
タプルへの値の追加は,2回目・3回目と同様です.リストへの値の追加による振る舞いが,変わりました.「c + [6]」により,[1, 2, 3, 4, 5, 6]となる新たなリストが作られ,「c = そのリスト」により参照します.その一方で,変数dの参照は変わらず,出力としては[1, 2, 3, 4, 5]です.図は次の通りです.
ここまでをまとめると,以下の通りとなります.
- 「b = a」により,aとbは同じタプルを参照している.
- 「a = a + (4,)」を実行することで,aとbとで参照するタプルが変わる.
- 「d = c」により,cとdは同じリストを参照している.
- 「c.append(4)」や「c += [5]」を実行しても,cとdは同じリストを参照している.
- 「c = c + [6]」を実行することで,cとdとで参照するリストが変わる.
- 変数がリストを参照するとき,「変数 += 他のリスト」と「変数 = 変数 + 他のリスト」は異なる.
*1:ただし1点だけ注意することがあります.(1, 2, 3, 4)で表されるタプルを,aもbも参照しなくなりました.あとで示す図は,(1, 2, 3, 4)のタプルが(1, 2, 3, 4, 5)になった,というのではなく,(1, 2, 3, 4)のタプルと別に,(1, 2, 3, 4, 5)のタプルが新たに作られて,aがそれを参照する,と考えないといけません.