耳慣れない用語「タプル (tuple)」。
調べてみるとPythonだけではなく、C#7でも導入されているようですね。
リスト (list) に似ているけど、違うもの。
じゃあどう違うんだろう。どんな時に使うんだろう。
という訳で、本稿スタートです。
タプル (tuple) とは
タプル (tuple) はイミュータブル (immutable) なシーケンスで・・・
なんのこっちゃ。。。
* イミュータブル (immutable) とは・・・作成後にその状態を変えることができないことを指す
* シーケンス型 とは・・・基本的なものとしては 「リスト (list)」「タプル (tuple)」「rangeオブジェクト」
語弊を恐れずざっくりいうと、
タプルとは・・・
|
ということですね。
要素の追加・削除もそうですが、要素の値が変更できないということはソートもできないということです。 *リスト (list) に変換してソートすることは可能。
実際、dir関数でメソッドを調べると以下のようになっています。(Python 3.8)
# | メソッド (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) | 備考 |
---|---|---|---|---|
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) が不変なオブジェクトだからこそですよね。値が変わってしまう可能性のある リスト (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) で返してくるから、好き嫌い言わずに使わざるを得ないんだよね。
コメント