ゼロからのPython入門講座タプルとコレクション タプル

タプルコレクションシーケンスコレクションのアンパック

世の中のデータにはさまざまな種類があり、中には複数のデータから構成されているものがあります。例えば、

  • 東京都の人形町駅の位置は、緯度と経度で表すと、緯度 35.686321、 経度 139.782211 という2つの数値の組み合わせから構成されます。
  • 日本での氏名は、名字と名前という2つの文字列の組み合わせから構成されます。
  • 日本の年号は、昭和・平成などの元号と、2030 などの数値の組み合わせから構成されます。
  • 色は、赤・緑・青の三原色を表す3つの数値の組み合わせで表現できます。例えば、黄色は赤 255、緑 255、 青 0 という組み合わせです。

このように、一つの情報が、複数の情報の組み合わせから構成されている、というのは非常に一般的です。

タプル

Pythonでは、このような複数のデータの組み合わせから構成されているデータを表現する場合、タプル という種類のオブジェクトを利用します。

タプル(tuple)というのはあんまり聞き慣れない言葉ですが、 などとも呼ばれ、複数の要素が決まった順番にならんだ値を指します。

タプルの書き方

タプルオブジェクトは、複数の値をカンマ , で区切って記述します。例えば、上記の人形町駅の位置は、緯度と経度をタプルであらわすと次のようになります。

In [2]:
ningyocho = 35.686321, 139.782211
print(ningyocho)
(35.686321, 139.782211)

緯度 35.686321 と、経度 139.782211 をカンマ , で区切って記述し、一つのタプルオブジェクトとして 変数 ningyocho に代入しています。

また、平成2年 は、平成 と言う文字列と、数値の 2 の組み合わせですから、これもカンマ , で区切って

In [3]:
kotoshi = '平成', 2
print(kotoshi)
('平成', 2)

と書けます。

タプルは、このように要素となるデータを , で区切って記述できますが、, だけだとちょっと見にくいので、通常は全体を丸括弧 () で囲んで記述します。

例えば、前述の ningyochokotoshi は、次のように書きます。

In [13]:
ningyocho = (35.686321, 139.782211)
kotoshi = ('平成', 2)

この括弧は必須ではありませんが、括弧なしでは読みにくく、間違いの元になる場合もあるので、通常は括弧をつけて記述する慣習になっています。

タプルオブジェクトの要素を参照する

タプルオブジェクトに登録したオブジェクトは、リスト と同じように 要素の順番 を指定して参照できます。

タプルオブジェクト[要素の順番]

要素の順番 として指定する数値のことを、リストオブジェクトと同じように インデックス(添字) と呼びます。

人形町駅の緯度と経度のタプルは

ningyocho = (35.686321, 139.782211)

でした。このタプルから、緯度と経度を取り出してみましょう。ningyocho(緯度, 経度) という形式のタプルオブジェクトですから、最初の要素が緯度、次の要素が経度です。

最初の要素はインデックスに 0 を、次の要素はインデックスとして 1 を指定して参照できますから、緯度と経度は次のようにして取り出せます。

In [15]:
ningyocho = (35.686321, 139.782211)

ido = ningyocho[0]  # 緯度は先頭の要素
keido = ningyocho[1]  # 緯度は次の要素

print("人形町の緯度は", ido, "経度は", keido, "です")
人形町の緯度は 35.686321 経度は 139.782211 です

タプルの比較演算子

タプルは、数値や文字列と同じように、比較演算子 を使って他のタプルと値を比較できます。

== 演算子でタプル同士を比較すると、同じ値のタプルならTrue を返します。

In [71]:
value1 = (1, 2, 3)
value2 = (1, 2, 3)

print(value1 == value2) # 同じ値なので True となる
True

等しくなければ、False を返します。

In [70]:
value1 = (1, 2, 3)
value3 = (2, 3, 4)

print(value1 == value3) # 異なる値なので False となる
False

同様に、 != 演算子でタプル同士を比較すると、異なる値のタプルなら True、等しい値なら False を返します。

In [73]:
value1 = (1, 2, 3)
value2 = (1, 2, 3)
value3 = (2, 3, 4)

print(value1 != value2) # 同じ値なので False となる
print(value1 != value3) # 異なる値なので True となる
False
True

<<=>>= などの演算子で、タプル同士の大小を判定できます。

In [75]:
value1 = (1, 2, 3)
value2 = (1, 2, 4)

print(value1 < value2) # value1 < value2 なので True となる
True

タプル同士の値の比較は、先頭の要素から順番に同じインデックス同士の値を比較して、先に小さい値となったタプルが小さい値となります。

例えば、上記のように (1, 2, 3)(1, 2, 4) を比較した場合、

  1. 最初の要素の 11 を比較する。同じ値なので、次の値をチェックする。
  2. 2番めの要素の 22 を比較する。同じ値なので、次の値をチェックする。
  3. 3番目の要素の 34 を比較する。 3 < 4 なので、(1, 2, 3)(1, 2, 4) よりも小さい。

のように比較を行います。

比較するタプル同士の長さが異なる場合、短いタプルの要素と長いタプルの要素を比較してすべて等しければ、短い要素のほうが小さい値となります。

たとえば、長さが 3 のタプル (1, 2, 3) と、長さが 4 のタプル (1, 2, 3, 4)は、長さ 3 のタプルの要素はすべて長さ 4 のタプルと一致しますので、長さが短い (1, 2, 3) が小さい値のタプルとなります。

In [76]:
value1 = (1, 2, 3)
value2 = (1, 2, 3, 4)

print(value1 < value2)
True

タプルオブジェクトの操作

リストオブジェクトの場合は、要素を参照する以外に、追加や削除、変更などの操作 を行えます。次の例は、数値の 1, 2, 3 からなるリストを作成したあと、最初の要素を文字列の a に書き換えています。

In [43]:
sample = [1, 2, 3] # リストオブジェクトの作成
sample[0] = 'a' #  要素の更新
print(sample)
['a', 2, 3]

しかし、タプルオブジェクトの場合、リストオブジェクトのように要素を変更することはできません。タプルオブジェクトの要素を変更する場合は、リストオブジェクトのように要素を変更するのではなく、あたらしくタプルオブジェクト全体を作り直す必要があります。

たとえば、color という変数に、色の情報を三原色(赤・緑・青) のタプルとして黄色 (255, 255, 0) が設定されているとします。

In [44]:
color = (255, 255, 0)  # 黄色
print(color)
(255, 255, 0)

color の色を、黄色 (255, 255, 0) から赤 (255, 0, 0) に変更したい場合でも、リストオブジェクトのように値を更新することはできません。次のようなエラーになります。

In [45]:
color[1] = 0  # 緑色を 0 に変更
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-45-8f192bf0a20a> in <module>
----> 1 color[1] = 0  # 緑色を 0 に変更

TypeError: 'tuple' object does not support item assignment

color の要素の値を変更する場合は、タプルの要素を変更するのではなく、新しくタプルを作り、変数 color に代入して更新します。

In [46]:
color = (255, 0, 0)  # 赤
print(color)
(255, 0, 0)

タプルとリスト

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

どちらも他のデータを格納できるコンテナオブジェクトで、格納した要素は数値をインデックスとして参照できます。リストにはデータを追加したり削除したりできますが、タプルは変更できません。タプルとリストの見た目もよく似ています。

list_values = [1, 2, 3]  # リスト
tuple_values = (1, 2, 3) # タプル

リストとタプルはどのように使い分ければよいのでしょうか?

前述のように、タプルは

複数のデータの組み合わせから構成されているデータ

のためのオブジェクトです。

次の例は、学校である生徒の定期テストの結果をデータとして記述しています。

sugaku = 50  # 数学の点数
kokugo = 60  # 国語の点数
eigo = 70  # 英語の点数

exam_scores = (sugaku, kokugo, eigo)

exam_scores は、ある生徒の成績を

(数学の点数, 国語の点数, 英語の点数)

という決まったルールで記述した、固定的な形式のデータです。

このように、複数の要素から構成される独立したデータ をあらわすときは、タプルを使用します。

もう一つの例として、たくさんの生徒のテストの点数を、教科ごとにまとめたデータを考えてみましょう。

sugaku_scores = [82, 12, 12, 94, 86, 5]
kokugo_scores = [99, 64, 99, 39, 56, 1, 77, 57, 82, 75, 5, 74, 3]
eigo_scores = [16, 81, 82, 47, 80, 48, 10, 72, 81, 7]

ここで定義した変数 sugaku_scoreskokugo_scoreseigo_scores は、それぞれ数学、国語、英語の、全受験者の点数をまとめたリストです。それぞれの教科では受験者数が違うため、要素数も全て異なっています。

このように、固定的な形式をもつ独立したデータではなく、不定個数の独立したデータをたくさん集約してまとめておきたい、という用途には、リストが適しています。

もちろん、タプルを使わず、常にリストを使用することもできますが、その場合次のようなデメリットが考えられます。

  • exam_scores のようにタプルで作られたデータは、あとからプログラムを参照する人に 「これは複数の値から構成されるデータだ」 という情報を伝え、プログラムの意図を理解する助けになります。リストにしてしまうと、間違った意図を伝えることになります。

  • タプルは個別のデータをあらわすオブジェクトなので、非常にたくさんのオブジェクトが使用されても効率的に処理できるようになっています。

    テストの例で考えると、受験者が100万人いた場合は exam_scores のようなデータが100万個作られることになります。タプルの場合には100万件のデータを作っても最小限の負荷で抑えられますが、リストで同じデータを100万個作ると、タプルと比べて大きな負荷がかかります。

Copyright © 2001-2023 python.jp Privacy Policy python_japan
Amazon.co.jpアソシエイト
Amazonで他のPython書籍を検索