この記事では、Pythonのタプルの使い方について、初心者の方にも分かりやすく解説を進めていきます!
Pythonにはリストっていう便利なやつがあるけど、タプルって何が違うの?
いつ使うの?
そんな疑問をスッキリ解決しちゃいましょう。この記事を読めば、タプルの基本から、リストとの違い、実際の活用シーンまで丸わかり。
読み終わるころには、自信を持ってタプルを使いこなせるようになっているはずですよ!
この記事で学べること
- タプルの基本的な作り方やアクセス方法
- リストとタプルの根本的な違い
- タプルが変更できない理由とその利点
- タプルが活躍する具体的な場面
- タプルを使う上での注意点と対処法
- タプルの便利なメソッドの使い方
Pythonのタプルとは?リストとの違いを知ろう
Pythonのタプル(tuple)は、複数のデータをひとまとめにして扱えるデータ型の一つです。見た目はリスト(list)に似ていますが、決定的な違いがあります。
それは、タプルは一度作成したら、中の要素を変更したり、追加したり、削除したりできない、ということです。いわゆるイミュータブル(不変)ってやつですね。
一方、リストは要素の変更、追加、削除が自由自在。ミュータブル(可変)と呼ばれます。
イメージとしては、こんな感じです。
リスト:[リンゴ, ゴリラ, ラッパ] <-- 後からバナナを追加したり、ゴリラを削除したりできる! タプル:(赤, 青, 黄) <-- 信号機の色みたいに、一度決めたら基本的に変わらない!
なぜ変更できないタプルが存在するかというと、変更できないことによるメリットがあるからなんです。
例えば、プログラムの途中で勝手に書き換えられたくないデータ(設定値とか)を守ったり、辞書というデータ構造のキーとして使えたりします。リストは変更できちゃうので、辞書のキーには使えません。
また、一般的には、タプルの方がリストよりも少しだけメモリの使用量が少なく、処理速度も速いと言われています。
まあ、微々たる差なので、普段はあまり気にしなくても大丈夫ですが、頭の片隅に置いておくと良いでしょう。
タプルの基本的な使い方作り方とアクセス方法
それでは、実際にタプルの基本的な使い方を見ていきましょう!
まずは作り方と、作ったタプルの要素を取り出す方法からマスターしていきましょう。
タプルの作成方法カンマ区切りとtuple関数
タプルを作る一番簡単な方法は、丸括弧 `()` で要素を囲み、カンマ `,` で区切ることです。丸括弧は省略することも可能ですが、コードの分かりやすさのために付けるのが一般的ですね。
# 丸括弧とカンマで作成 my_tuple1 = (1, 2, 3) my_tuple2 = 'a', 'b', 'c' # 丸括弧は省略可能 print(my_tuple1) print(type(my_tuple1)) print(my_tuple2) print(type(my_tuple2))
実行結果はこうなります。
(1, 2, 3) <class 'tuple'> ('a', 'b', 'c') <class 'tuple'>
リストなどの他のデータ構造からタプルを作りたい場合は、`tuple()` 関数を使います。
# リストからタプルを作成 my_list = [10, 20, 30] tuple_from_list = tuple(my_list) print(tuple_from_list) print(type(tuple_from_list))
実行結果です。
(10, 20, 30) <class 'tuple'>
これでタプルの基本的な作成はバッチリですね!
タプルの要素へのアクセスインデックス指定
タプルの中の特定の要素を取り出したいときは、リストと同じようにインデックス(番号)を使います。インデックスは `0` から始まることを覚えておきましょう!
my_tuple = ('apple', 'banana', 'cherry') # 最初の要素(インデックス0) print(my_tuple[0]) # 2番目の要素(インデックス1) print(my_tuple[1]) # 最後の要素(インデックス-1 or 2) print(my_tuple[-1]) print(my_tuple[2])
実行結果です。
apple banana cherry cherry
インデックスに `-1` を指定すると、末尾の要素にアクセスできます。 `-2` なら最後から2番目、という具合です。これもリストと同じですね。
タプルのスライス部分的な取り出し方
タプルの中から、一部分だけを新しいタプルとして取り出したい場合は、「スライス」を使います。これもリストと同じ感覚で使えますよ。
書き方は `タプル[開始インデックス:終了インデックス]` です。終了インデックスの要素は含まれない点に注意してください。
numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) # インデックス1から3の手前まで (1, 2) print(numbers[1:3]) # 最初の要素からインデックス4の手前まで (0, 1, 2, 3) print(numbers[:4]) # インデックス5から最後まで (5, 6, 7, 8, 9) print(numbers[5:]) # 全ての要素 print(numbers[:]) # 1つ飛ばしで要素を取り出す (0, 2, 4, 6, 8) print(numbers[::2])
実行結果です。
(1, 2) (0, 1, 2, 3) (5, 6, 7, 8, 9) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) (0, 2, 4, 6, 8)
開始や終了を省略したり、ステップ(何個飛ばしで取り出すか)を指定したりもできます。色々試してみてくださいね。
なぜ変更できないの?タプルの不変性とそのメリット
さて、タプルの最大の特徴である「変更できない」性質、つまり不変性(イミュータブル)についてもう少し掘り下げてみましょう。
タプルでは、一度作成した後に要素の値を書き換えたり、新しい要素を追加したり、既存の要素を削除したりすることはできません。無理に変更しようとすると、エラーが発生します。
my_tuple = (10, 20, 30) # 要素を変更しようとするとエラー! # my_tuple[0] = 100 # TypeError: 'tuple' object does not support item assignment # 要素を追加しようとしてもメソッドがない(エラー!) # my_tuple.append(40) # AttributeError: 'tuple' object has no attribute 'append' # 要素を削除しようとしてもメソッドがない(エラー!) # del my_tuple[0] # TypeError: 'tuple' object doesn't support item deletion
このように、プログラムがエラーを出して変更を阻止してくれるのです。
一見不便に感じるかもしれませんが、変更できないことには大きなメリットがあります。
- データの安全性が高まる
プログラムのどこかで意図せずにデータが書き換えられてしまう心配がありません。定数のように、変わってほしくない値を安全に保持できます。 - 辞書のキーとして使える
辞書のキーは、後から変わってしまうものであってはいけません。変更できないタプルなら、安心して辞書のキーとして利用できます。(座標データなど、複数の値をまとめてキーにしたい場合に便利!) - パフォーマンスが良い(場合がある)
前述の通り、リストに比べてメモリ効率や処理速度が少し良い傾向があります。膨大なデータを扱う場合などに恩恵があるかもしれません。
「変更できない」ことは、制限であると同時に、プログラムの安定性や安全性を高めるための強力な特性なのです。
タプルの具体的な活用シーン5選
理屈は分かったけど、実際にどんな場面でタプルを使うのが効果的なの?
という疑問にお答えします!リストではなくタプルを選ぶべき具体的なシーンを5つ見ていきましょう。
関数の戻り値で複数の値を返す
関数で計算した結果など、複数の値をまとめて返したいとき、タプルは非常に便利です。関数は通常一つの値しか返せませんが、タプルを使えば実質的に複数の値を返すことができます。
def get_user_info(): name = "Taro Yamada" age = 30 city = "Tokyo" # 複数の値をカンマ区切りで返すと、タプルとして返される return name, age, city # 関数の戻り値を受け取る user_data = get_user_info() print(user_data) print(type(user_data)) # アンパックして個別の変数に受け取ることも可能 user_name, user_age, user_city = get_user_info() print(user_name) print(user_age) print(user_city)
実行結果です。
('Taro Yamada', 30, 'Tokyo') <class 'tuple'> Taro Yamada 30 Tokyo
戻り値をタプルで受け取り、必要に応じてアンパックするのはPythonではよく使われるテクニックです。
辞書のキーとして利用する
前述の通り、辞書のキーは不変である必要があります。そのため、変更可能なリストはキーとして使えませんが、不変のタプルはキーとして使用できます。
例えば、地図の座標(緯度、経度)をキーとして、場所の名前を値とする辞書を作りたい場合などに役立ちます。
# (緯度, 経度) をキーにした辞書 locations = { (35.6895, 139.6917): "Tokyo", (40.7128, -74.0060): "New York", # 経度はマイナスもあり得る (34.0522, -118.2437): "Los Angeles" } # キー(タプル)を指定して値を取得 print(locations[(35.6895, 139.6917)]) # 新しい場所を追加 locations[(48.8566, 2.3522)] = "Paris" print(locations) # リストをキーにしようとするとエラーになる! # error_dict = {[1, 2]: "value"} # TypeError: unhashable type: 'list'
実行結果です。
Tokyo {(35.6895, 139.6917): 'Tokyo', (40.7128, -74.006): 'New York', (34.0522, -118.2437): 'Los Angeles', (48.8566, 2.3522): 'Paris'}
複数の値を組み合わせたものを一意なキーとして扱いたい場合、タプルは最適です。
フォーマット文字列への値の埋め込み
Pythonには文字列の中に変数の値を埋め込む方法がいくつかありますが、古い形式の `%` 演算子を使った方法や `str.format()` メソッドでは、複数の値をタプルで渡すことができます。
(現在ではf-string `f"{変数名}"` が主流ですが、古いコードや特定の場面でこれらの方法が使われることもあります。)
name = "Alice" age = 25 # %演算子を使った方法 print("Name: %s, Age: %d" % (name, age)) # str.format() メソッドを使った方法 print("Name: {}, Age: {}".format(name, age)) # 渡す値をタプルにまとめる user_data = (name, age) print("Name: %s, Age: %d" % user_data) print("Name: {}, Age: {}".format(*user_data)) # * を付けてアンパックする
実行結果です。
Name: Alice, Age: 25 Name: Alice, Age: 25 Name: Alice, Age: 25 Name: Alice, Age: 25
複数の値をセットとして扱って文字列に埋め込みたい場合に、タプルが役立つことがあります。
データの安全性を高めたい場合
プログラムの中で絶対に変わってほしくない設定値や定数のようなデータを扱う場合、リストよりもタプルで定義する方が安全です。
例えば、ゲームの設定でRGBカラーコードを定義する場合などです。
# 色の定義 (R, G, B) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) # このタプルは変更できないので、プログラムのどこかで # 誤って RED = (128, 0, 0) のように書き換えられる心配がない print(f"赤色のコードは: {RED}") # もしリストで定義していたら... # WRONG_RED = [255, 0, 0] # WRONG_RED[0] = 128 # 意図せず変更できてしまう可能性がある
実行結果です。
赤色のコードは: (255, 0, 0)
値が変わらないことを保証したいデータには、積極的にタプルを使いましょう。
パフォーマンスを意識する場合
これは少しマニアックな話ですが、一般的にタプルはリストと比較して、メモリの使用効率が良く、要素へのアクセス速度もわずかに速いとされています。
何百万もの大量のデータを扱ったり、処理速度がミリ秒単位で要求されるようなシビアな場面では、リストの代わりにタプルを使うことでパフォーマンスの改善が見込めるかもしれません。
# 大量の座標データなど # points_list = [(x, y) for x in range(1000) for y in range(1000)] # タプルのリスト # points_tuple = tuple((x, y) for x in range(1000) for y in range(1000)) # タプルのタプル (さらに効率的かも) # ※実際のパフォーマンス差は処理内容や環境によります import sys my_list = [0, 1, 2, 3, 4, 5] my_tuple = (0, 1, 2, 3, 4, 5) print(f"リストのメモリサイズ: {sys.getsizeof(my_list)}") print(f"タプルのメモリサイズ: {sys.getsizeof(my_tuple)}")
実行結果の一例です(環境により多少異なります)。
リストのメモリサイズ: 120 タプルのメモリサイズ: 88
ただし、ほとんどのケースではリストとタプルのパフォーマンス差は無視できるレベルです。基本的には、データの性質(変更が必要か不要か)やコードの分かりやすさで選ぶのが良いでしょう。
タプルの便利なメソッド - countとindexの使い方
タプルは変更系のメソッド(appendやremoveなど)を持ちませんが、情報を取得するための便利なメソッドがいくつか用意されています。
ここでは代表的な `count()` と `index()` を紹介します。
- `count(要素)`: タプルの中に指定した要素が何個含まれているかを数えて返します。
- `index(要素)`: タプルの中に指定した要素が最初に現れるインデックス(位置番号)を返します。もし要素が存在しない場合はエラーになります。
my_tuple = (1, 2, 'a', 'b', 2, 'a', 2) # '2' が何個あるか数える count_of_2 = my_tuple.count(2) print(f"'2'の個数: {count_of_2}") # 'a' が何個あるか数える count_of_a = my_tuple.count('a') print(f"'a'の個数: {count_of_a}") # 'c' が何個あるか数える (存在しない) count_of_c = my_tuple.count('c') print(f"'c'の個数: {count_of_c}") # 'b' が最初に現れるインデックスを探す index_of_b = my_tuple.index('b') print(f"'b'のインデックス: {index_of_b}") # '2' が最初に現れるインデックスを探す index_of_2 = my_tuple.index(2) print(f"'2'の最初のインデックス: {index_of_2}") # 'z' のインデックスを探そうとするとエラー! # index_of_z = my_tuple.index('z') # ValueError: tuple.index(x): x not in tuple
実行結果です。
'2'の個数: 3 'a'の個数: 2 'c'の個数: 0 'b'のインデックス: 3 '2'の最初のインデックス: 1
これらのメソッドは、特定の要素の存在確認や位置を知りたいときに役立ちますね。
タプルの使い方で注意すべき点
タプルは便利ですが、いくつか注意しないと予期せぬエラーや挙動につながることがあります。初心者がハマりやすいポイントとその対処法を見ていきましょう。
要素が1つのタプルを作成する場合の注意点
要素が一つだけのタプルを作りたい場合、ちょっとしたコツが必要です。
普通に丸括弧で囲むだけだと、タプルではなく、ただの括弧付きの値として扱われてしまいます。
要素が1つのタプルを作るには、要素の後ろに必ずカンマ `,` を付ける必要があります。
# これはタプルではない! ただの整数 10 not_a_tuple = (10) print(not_a_tuple) print(type(not_a_tuple)) # 要素の後ろにカンマを付けるとタプルになる! single_element_tuple = (10,) # <-- ここにカンマ! print(single_element_tuple) print(type(single_element_tuple)) # 文字列の場合も同様 string_tuple = ('hello',) print(string_tuple) print(type(string_tuple))
実行結果です。
10 <class 'int'> (10,) <class 'tuple'> ('hello',) <class 'tuple'>
うっかりカンマを忘れると、後々タプルとして扱えずにエラーになることがあるので、しっかり覚えておきましょう!
タプル内のミュータブルな要素の変更
これは少し応用的な話ですが、タプル自体は不変(イミュータブル)でも、そのタプルの要素としてリストのようなミュータブル(可変)なオブジェクトが含まれている場合、そのリスト自体の内容は変更できてしまいます。
ちょっとややこしいですが、例を見てみましょう。
# タプルの要素にリストが含まれている my_tuple = (1, 2, ['a', 'b']) print(f"変更前のタプル: {my_tuple}") # タプル内のリストの要素を変更する # タプル自体を変更しているわけではない my_tuple[2][0] = 'X' # リストの最初の要素を 'X' に変更 print(f"変更後のタプル: {my_tuple}") # タプルの中のリストが変わっている! # タプルの要素(リスト自体)を別のリストに置き換えようとするとエラー # my_tuple[2] = ['c', 'd'] # TypeError: 'tuple' object does not support item assignment
実行結果です。
変更前のタプル: (1, 2, ['a', 'b']) 変更後のタプル: (1, 2, ['X', 'b'])
タプルは、あくまでも「どの要素を指しているか」という情報が変更できないだけで、その指している先のオブジェクトがリストのように変更可能な場合は、その中身は変えられてしまうのです。
この挙動は混乱を招くことがあるので、タプルの要素にミュータブルなオブジェクトを入れる場合は注意が必要です。
【まとめ】Pythonタプルの使い方をマスターしてレベルアップ!
この記事では、Pythonのタプルについて、基本的な使い方からリストとの違い、変更できないことのメリット、具体的な活用シーン、そして注意点まで解説してきました。
最後に、今回のポイントをまとめておきましょう。
- タプルは `()` と `,` で作る、変更できないデータ構造。
- リストと違い、要素の追加・変更・削除ができない(不変)。
- 不変性により、データの安全性が高まり、辞書のキーにも使える。
- 関数の複数の戻り値や、設定値の保持などに便利。
- 要素が1つのタプルは `(要素,)` のようにカンマが必要。
- `count()` や `index()` メソッドで情報を取得できる。
タプルはリストほど頻繁に使うわけではないかもしれませんが、その特性を理解して適切な場面で使うことで、より安全で効率的な、そしてPythonらしいコードを書くことができます。
今日学んだことを活かして、ぜひ実際のコードでタプルを使ってみてください。例えば、簡単な関数を作って複数の値をタプルで返してみたり、座標データをキーにした辞書を作ってみたりするのも良い練習になりますよ。
【関連記事】 「Pythonとは?」に答える最初の一歩
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。