世の中のデータにはさまざまな種類があり、中には複数のデータから構成されているものがあります。例えば、
- 東京都の人形町駅の位置は、緯度と経度で表すと、緯度
35.686321
、 経度139.782211
という2つの数値の組み合わせから構成されます。 - 日本での氏名は、名字と名前という2つの文字列の組み合わせから構成されます。
- 日本の年号は、昭和・平成などの元号と、
20
や30
などの数値の組み合わせから構成されます。 - 色は、赤・緑・青の三原色を表す3つの数値の組み合わせで表現できます。例えば、黄色は赤
255
、緑255
、 青0
という組み合わせです。
このように、一つの情報が、複数の情報の組み合わせから構成されている、というのは非常に一般的です。
タプル¶
Pythonでは、このような複数のデータの組み合わせから構成されているデータを表現する場合、タプル という種類のオブジェクトを利用します。
タプル(tuple)というのはあんまり聞き慣れない言葉ですが、組 などとも呼ばれ、複数の要素が決まった順番にならんだ値を指します。
タプルの書き方¶
タプルオブジェクトは、複数の値をカンマ ,
で区切って記述します。例えば、上記の人形町駅の位置は、緯度と経度をタプルであらわすと次のようになります。
ningyocho = 35.686321, 139.782211
print(ningyocho)
緯度 35.686321
と、経度 139.782211
をカンマ ,
で区切って記述し、一つのタプルオブジェクトとして 変数 ningyocho
に代入しています。
また、平成2年
は、平成
と言う文字列と、数値の 2
の組み合わせですから、これもカンマ ,
で区切って
kotoshi = '平成', 2
print(kotoshi)
と書けます。
タプルは、このように要素となるデータを ,
で区切って記述できますが、,
だけだとちょっと見にくいので、通常は全体を丸括弧 ()
で囲んで記述します。
例えば、前述の ningyocho
や kotoshi
は、次のように書きます。
ningyocho = (35.686321, 139.782211)
kotoshi = ('平成', 2)
この括弧は必須ではありませんが、括弧なしでは読みにくく、間違いの元になる場合もあるので、通常は括弧をつけて記述する慣習になっています。
タプルオブジェクトの要素を参照する¶
タプルオブジェクトに登録したオブジェクトは、リスト と同じように 要素の順番 を指定して参照できます。
タプルオブジェクト[要素の順番]
要素の順番
として指定する数値のことを、リストオブジェクトと同じように インデックス(添字) と呼びます。
人形町駅の緯度と経度のタプルは
ningyocho = (35.686321, 139.782211)
でした。このタプルから、緯度と経度を取り出してみましょう。ningyocho
は (緯度, 経度)
という形式のタプルオブジェクトですから、最初の要素が緯度、次の要素が経度です。
最初の要素はインデックスに 0
を、次の要素はインデックスとして 1
を指定して参照できますから、緯度と経度は次のようにして取り出せます。
ningyocho = (35.686321, 139.782211)
ido = ningyocho[0] # 緯度は先頭の要素
keido = ningyocho[1] # 緯度は次の要素
print("人形町の緯度は", ido, "経度は", keido, "です")
value1 = (1, 2, 3)
value2 = (1, 2, 3)
print(value1 == value2) # 同じ値なので True となる
等しくなければ、False
を返します。
value1 = (1, 2, 3)
value3 = (2, 3, 4)
print(value1 == value3) # 異なる値なので False となる
同様に、 !=
演算子でタプル同士を比較すると、異なる値のタプルなら True
、等しい値なら False
を返します。
value1 = (1, 2, 3)
value2 = (1, 2, 3)
value3 = (2, 3, 4)
print(value1 != value2) # 同じ値なので False となる
print(value1 != value3) # 異なる値なので True となる
<
、 <=
、>
、>=
などの演算子で、タプル同士の大小を判定できます。
value1 = (1, 2, 3)
value2 = (1, 2, 4)
print(value1 < value2) # value1 < value2 なので True となる
タプル同士の値の比較は、先頭の要素から順番に同じインデックス同士の値を比較して、先に小さい値となったタプルが小さい値となります。
例えば、上記のように (1, 2, 3)
と (1, 2, 4)
を比較した場合、
- 最初の要素の
1
と1
を比較する。同じ値なので、次の値をチェックする。 - 2番めの要素の
2
と2
を比較する。同じ値なので、次の値をチェックする。 - 3番目の要素の
3
と4
を比較する。3
<4
なので、(1, 2, 3)
は(1, 2, 4)
よりも小さい。
のように比較を行います。
比較するタプル同士の長さが異なる場合、短いタプルの要素と長いタプルの要素を比較してすべて等しければ、短い要素のほうが小さい値となります。
たとえば、長さが 3
のタプル (1, 2, 3)
と、長さが 4
のタプル (1, 2, 3, 4)
は、長さ 3
のタプルの要素はすべて長さ 4
のタプルと一致しますので、長さが短い (1, 2, 3)
が小さい値のタプルとなります。
value1 = (1, 2, 3)
value2 = (1, 2, 3, 4)
print(value1 < value2)
タプルオブジェクトの操作¶
リストオブジェクトの場合は、要素を参照する以外に、追加や削除、変更などの操作 を行えます。次の例は、数値の 1
, 2
, 3
からなるリストを作成したあと、最初の要素を文字列の a
に書き換えています。
sample = [1, 2, 3] # リストオブジェクトの作成
sample[0] = 'a' # 要素の更新
print(sample)
しかし、タプルオブジェクトの場合、リストオブジェクトのように要素を変更することはできません。タプルオブジェクトの要素を変更する場合は、リストオブジェクトのように要素を変更するのではなく、あたらしくタプルオブジェクト全体を作り直す必要があります。
たとえば、color
という変数に、色の情報を三原色(赤・緑・青) のタプルとして黄色 (255, 255, 0)
が設定されているとします。
color = (255, 255, 0) # 黄色
print(color)
color
の色を、黄色 (255, 255, 0)
から赤 (255, 0, 0)
に変更したい場合でも、リストオブジェクトのように値を更新することはできません。次のようなエラーになります。
color[1] = 0 # 緑色を 0 に変更
color
の要素の値を変更する場合は、タプルの要素を変更するのではなく、新しくタプルを作り、変数 color
に代入して更新します。
color = (255, 0, 0) # 赤
print(color)
タプルとリスト¶
タプルとリストはとてもよく似ています。
どちらも他のデータを格納できるコンテナオブジェクトで、格納した要素は数値をインデックスとして参照できます。リストにはデータを追加したり削除したりできますが、タプルは変更できません。タプルとリストの見た目もよく似ています。
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_scores
、kokugo_scores
、eigo_scores
は、それぞれ数学、国語、英語の、全受験者の点数をまとめたリストです。それぞれの教科では受験者数が違うため、要素数も全て異なっています。
このように、固定的な形式をもつ独立したデータではなく、不定個数の独立したデータをたくさん集約してまとめておきたい、という用途には、リストが適しています。
もちろん、タプルを使わず、常にリストを使用することもできますが、その場合次のようなデメリットが考えられます。
exam_scores
のようにタプルで作られたデータは、あとからプログラムを参照する人に 「これは複数の値から構成されるデータだ」 という情報を伝え、プログラムの意図を理解する助けになります。リストにしてしまうと、間違った意図を伝えることになります。タプルは個別のデータをあらわすオブジェクトなので、非常にたくさんのオブジェクトが使用されても効率的に処理できるようになっています。
テストの例で考えると、受験者が100万人いた場合は
exam_scores
のようなデータが100万個作られることになります。タプルの場合には100万件のデータを作っても最小限の負荷で抑えられますが、リストで同じデータを100万個作ると、タプルと比べて大きな負荷がかかります。