タプル(tuple)ってなんだ?

知恵袋・テクニック

耳慣れない用語「タプル (tuple)」。
調べてみるとPythonだけではなく、C#7でも導入されているようですね。
リスト (list) に似ているけど、違うもの。
じゃあどう違うんだろう。どんな時に使うんだろう。

という訳で、本稿スタートです。

タプル (tuple) とは

タプル (tuple)イミュータブル (immutable) シーケンスで・・・

Python チュートリアル タプル型 より

なんのこっちゃ。。。

* イミュータブル (immutable) とは・・・作成後にその状態を変えることができないことを指す
* シーケンス型 とは・・・基本的なものとしては 「リスト (list)」「タプル (tuple)」「rangeオブジェクト」

語弊を恐れずざっくりいうと、

タプルとは・・・

  • 要素の追加・削除や、要素の値の変更ができない
  • リスト (list) のようなオブジェクト

ということですね。

要素の追加・削除もそうですが、要素の値が変更できないということはソートもできないということです。 *リスト (list) に変換してソートすることは可能。

実際、dir関数でメソッドを調べると以下のようになっています。(Python 3.8)

タプル (tuple) と リスト (list) のメソッド比較
メソッド (method) 説明 タプル (tuple) リスト (list) 備考
1 count 指定値の出現回数
2 index 指定値探索・・・最初に該当した要素のインデックスを返す
3 append 末尾への要素追加 (1要素)
4 clear 全要素除去
5 copy オブジェクトのコピー シャローコピー (shallow copy)
6 extend 拡張=末尾への複数要素追加
7 insert 要素の挿入
8 pop 要素の取り出し 取り出した要素は除去
9 remove 指定値を持つ要素の削除
10 reverse 逆転
11 sort ソート

また、演算としては、下表のとおり。(Python 3.8)

タプル (tuple) と リスト (list) の演算比較
演算 タプル (tuple) リスト (list) 備考
1 in / not in の使用
2 + による結合 タプル (tuple) の場合、新たなオブジェクトが生成される
3 * による繰返し
4 指定インデックスでの要素の値取得
5 スライス式
6 組込関数 len による長さ取得
7 組込関数 min による最小値取得
8 組込関数 max による最大値取得
9 指定要素への値代入
10 del式 による 指定要素の削除

じゃあリスト (list) でいいじゃん!と思ったアナタ

実際のコーディング上で、例えばデータベースから値をとってきて、リスト (list) に放り込むことを考えてみましょう。

要素の追加、削除とか、値の変更、やってますか?

することもあるだろうし、しないこともあるとは思いますが、意外に取ってきたデータをそのまま使っていることも多いのではないですか?

特に設定系データを利用するようなケースでは、不用意に値を書き換えてしまうのはよくないので、その場合には タプル (tuple)イミュータブル (immutable) な性質 (追加・削除、変更できないという性質)が意味を持ちます。

タプル (tuple)イミュータブル (immutable) な性質から、さらに下記のような特性もあります。

  • タプル (tuple) は、辞書 (dictionary) のキーとして使用できる
  • タプル (tuple) は、リスト (list) と比較してメモリ消費が抑えられ

前者は、タプル (tuple) が不変なオブジェクトだからこそですよね。値が変わってしまう可能性のある リスト (list) にはできないことです。

複数項目キーを持つ設定系データをPGM内に持ち込むために、複数項目キーを無理やり文字列連結して 辞書 (dictionary) に放り込んでた時代が懐かしいです。そんなことをしなくても タプル (tuple) をキーにしてやればコーディング上もスッキリです。

用途としても、地図データのマッピング(座標軸をキーにして)とか、画像認識(座標軸と色など)とかに使えるでしょう。

後者は、、、職業プログラマとしては「念頭においておく」という程度でいいのではないかと思います。もちろんメモリがシビアな状況では、メモリ消費を意識して リスト(list)  を極力使わず、タプル (tuple) を使う、という選択肢になるでしょう。(例えばロケット・人工衛星制御を、もしPythonで実装するのであれば、限られたリソースのなかでやりくりをしないといけないでしょう)

が、一般的なWEBアプリケーション、クライアントアプリケーションであれば、それほど気にする必要はない(メモリ圧迫はもっと別の要因であることが多い)と思われます。

なお、リスト (list)タプル (tuple) は相互変換可能です。

# リストからタプルへの変換
org_list = [1, 2, 3]
target_tuple = tuple(org_list) 

# タプルからリストへの変換
org_tuple = (1, 2, 3)
target_lsit = list(org_tuple)

タプル (tuple) で受け取ったデータを リスト (list) 化する場合は後者を使います。

タプル (tuple) の傾向、リスト (list) の傾向

リスト (list) は同じ特性を持ったデータの繰り返しとして格納されるケースが多いです。

for文やwhile文での繰り返しを見越したデータの格納のしかたですね。

一方で、タプル (tuple) は、同じ特性を持ったデータを扱うこともありますが、異なる特性をレコードデータ的に保持するケースがよくあります。

# タプルでの持ち方の例(氏名、身長、体重)
t1 = ('山田太郎', 175, 100)
t2 = ('鈴木一郎', 180, 75)

# これに対し、リストではこのように持ちがち
name_list = ['山田太郎', '鈴木一郎']
height_list = [175, 180]
weight_list = [100, 75]

タプル (tuple) で異なる特性を持つことに関連し、名前付きタプル (named tuple) を使った簡易クラス作成ができます。先ほどの例を 名前付きタプル (named tuple) で書き換えると、

from collections import namedtuple

# 名前付きタプル で、BaseballPlayerという簡易クラス的な型を作成
BaseballPlayer = namedtuple('BaseballPlayer', ('name', 'height', 'weight'))

# 名前付きタプル BaseballPlayer を用いて、オブジェクト生成
player1 = BaseballPlayer('山田太郎', 175, 100)
player2 = BaseballPlayer('鈴木一郎', 180, 75)

# 簡易的なクラスとして使える。
# クラスメンバーにアクセスするように、属性を参照可能。
print(player1.name)
print(player1.height)
print(player1.weight)

名前付きタプル (named tuple) は、タプル (tuple) なので、イミュータブル (immutable) です。値の参照はできますが、変更はできません。

とはいえ、リスト (list) で持つよりは直感的な持ち方ができ、上手に使えばプログラミングの幅が広がるでしょう。

最後に

以上、タプル (tuple) って何だろう、というところで悩んでいる方の一助になれば幸いです。

、、、最後に本音を少しだけ。結局、関数やメソッドが タプル (tuple) で返してくるから、好き嫌い言わずに使わざるを得ないんだよね。

コメント