Pythonのタプルとリストの違いと使い分け方

タプルとリストは非常によく似ています。

しかし、タプルはリストと比べて使えるメソッドは多くありません。そのため、「タプルは使う価値があるのか」と感じる方も少なくないでしょう。確かに、実際にコードを書く時は、タプルはリストほど使われる訳ではありません。

ただし、タプルとリストの最大の違いは、リストはミュータブル(変更可能)なオブジェクトであり、タプルはイミュータブル(変更不可能)なオブジェクトであるという点にあります。そのため、タプルは、日付やカレンダーなど、「一度決めたら後で変更することがないもの」を作る時に使います。

せっかくなので、このページでは、この点について詳しく解説したいと思います。

目次

1. リストを使った際に起こりうる問題

ミュータブル(変更可能)なオブジェクトであるリストを使った場合、次のような問題が起きるケースが、結構な頻度であります。

まず、新しいリストを作ります。

In [1]:
#リストを作ります。
list_a = [1, 2, 3]

1.1. 同一オブジェクトのリストを作る

コードを書いている途中で、 list_a と同じ要素を持つ新しいリストを作る必要が出て来ました。

そこで、新しい list_b は、 list_a を代入することで作成することにしました。この場合、両者は同一オブジェクトとして認識されます。オブジェクトについては、のちに解説しますので、今は読み進めてみてください。

ここでは、[1, 2, 3]という簡単なものですが、実際は、もっと長いコードを書く場合が多いので、既にあるリストの要素を代入して新しいリストを作ることは多々あります。

In [2]:
#効率化のために新しいリストを、上のlist_aを代入することで作ります。
list_b = list_a
In [3]:
#これでlist_aと同じ要素の値を持つlist_bを作りました。
list_b
Out[3]:
[1, 2, 3]

さてコードが進んで、list_a の要素を変更する必要が出てきました。ただし、list_b を変更する意図はありません。

そこで、以下のように list_a だけに変更を加えようとしてみました。

In [4]:
#コードを書いている途中で、list_aの値を変更することになったとします。
list_a[0] = 0
In [5]:
#これでlist_aの要素の値は変更されました。
list_a
Out[5]:
[0, 2, 3]

これで list_a の要素を変更することができましたね。しかし、プログラム全体を実行すると、不具合が出てしまいました。

なぜでしょうか?

実は、list_a の要素を変更した時に、同時に list_b にも同じ変更が加えられてしまったのです。

In [6]:
#この時、list_aを代入して作ったlist_bも変更されてしまいます。
list_b
Out[6]:
[0, 2, 3]

1.2. 要素の一部変更は同一オブジェクトにも影響する

なぜこのようなことが起きるのでしょうか?

それは、list_b は list_a を代入して作ったので、これらは「同一のオブジェクト」として認識されているからです。

こうしたことが起きる理由は「Pythonのリストの値とオブジェクトを比較する方法」で解説しているので、ここでは割愛しますが、ミュータブル(変更可能)なオブジェクトではこのようなことは往々にして起こり得ます。

そして、「なぜうまくいかないんだ!」と混乱する理由の1つでもあります。新しいリストを作る時に、他のリストを代入したり、式に入れたりしなければ、こうしたことは起こり難いのですが、効率的ではありません。

2. タプルを使うと不要な混乱を避けられる

そこで、このような混乱を避けたい時には、タプルを使うという方法があります。タプルはイミュータブル(変更不可能)なオブジェクトなので、こうしたことは起きないのですね。

実際に見てみましょう。

In [1]:
#タプルを作ります。
tuple_a = (1, 2, 3)
In [2]:
#新しいタプルを、上のtuple_aを代入することで作ります。
tuple_b = tuple_a
In [3]:
#tuple_aを確認します。
tuple_a
Out[3]:
(1, 2, 3)
In [4]:
#tuple_bも確認しましょう。
tuple_b
Out[4]:
(1, 2, 3)

ここまでは同じですね。

2.1. タプルはイミュータブルなので要素の一部変更はできない

ここで、タプルの要素を変更したくなったとします。しかし、タプルはイミュータブル(変更不可能)なオブジェクトなので、それは不可能です。実行すると、以下のようにTypeErrorになります。

In [5]:
#途中でtupleの要素を変更しようとしてみます。
tuple_a[0] = 9
Error
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-eae5b4eedabd> in <module>()
      1 #途中でtupleの要素を変更しようとしてみます。
----> 2 tuple_a[0] = 9
TypeError: 'tuple' object does not support item assignment

このように、タプルの要素を後になって変更することは不可能なので、リストの時のように、同じオブジェクトである他のリストまで変更されてしまい、混乱するということを防ぐことができます。

このような理由から、タプルは日付やカレンダーなど、一度作ったら、後で変更する余地がないものに使うことができます。同じ理由で、Pythonの辞書のキーとして使うという方法もありでしょう。

2.2. タプルでも変数の上書きは可能

なお、タプルは、要素を後で変更することができないだけで、以下のように上書きすることはできますので、勘違いのないようにしてください。

In [6]:
#ただし、tupleを再定義することはできます。
tuple_a = (9, 2, 3)
In [7]:
#確認しましょう。
tuple_a
Out[7]:
(9, 2, 3)
In [8]:
#この方法では、tuple_bに同じ変更は反映されません。
tuple_b
Out[8]:
(1, 2, 3)

この他にも、タプルはイミュータブルであることから、要素の追加や、ソートもできません。それぞれ、「Pythonのタプルに要素の追加はできない」「Pythonのタプルはソートできない」をご覧ください。

3. まとめ

いかがでしょうか。

リストとタプルは、ほとんど同じような使い方ができますが、リストはミュータブルなオブジェクトであり、タプルはイミュータブルなオブジェクトです。

そのため、タプルは、日付やカレンダーなど、「一度決めたら後で変更することがないもの」を作る時に使います。

このようなことも知っておくと、イミュータビリティについての知識も深まりますね。



よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

目次
閉じる