タプルの使い所
目次
1. このレッスンで学ぶこと
- タプルが適している場面
- リストとの使い分け
- タプルの実践的な活用方法
- namedtupleの紹介
2. タプルとは
タプルは、複数の値を順序付きで格納する、変更不可能(イミュータブル)なデータ構造です。
| 項目 | 説明 |
|---|---|
| 書き方 | (要素1, 要素2, 要素3, ...) |
| 変更 | 不可能 |
| 順序 | あり |
| 用途 | 固定データ、複数戻り値、辞書のキー |
主な特徴:
- 丸括弧
()で囲んで作成される - 一度作成すると変更できない(イミュータブル)
- インデックスとスライスでアクセス可能
- 辞書のキーとして使用できる(リストは不可)
簡単なコード例:
Python# 固定データの定義 RGB_RED = (255, 0, 0) RGB_GREEN = (0, 255, 0) print(f"赤: {RGB_RED}") print(f"第1要素: {RGB_RED[0]}") # 複数戻り値 def get_dimensions(): return 640, 480 # タプルで返される width, height = get_dimensions() print(f"画面サイズ: {width}x{height}")
3. なぜタプルを使うのか?
タプルには変更不可という特性があり、特定の状況で非常に有用です。
Python# 座標は変更されるべきでない ORIGIN = (0, 0) # RGB色は固定値 RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) # 設定値は保護したい DATABASE_CONFIG = ("localhost", 5432, "mydb", "user")
タプルを使うことで、データの整合性を保てます。
💡 豆知識: Pythonの内部では、タプルはリストよりも効率的に実装されています。ハッシュ可能なので辞書のキーにでき、メモリ使用量も少なくて済みます。
4. タプルが適している場面
1. 固定データ・定数
機能: 変更されるべきでないデータを保護します。
書き方:
Python定数 = (値1, 値2, ...)
用途: 設定値、座標、RGB色、曜日
注意点: 大文字の変数名を使うと定数であることが明確
Python# 曜日(変更されない) WEEKDAYS = ("月", "火", "水", "木", "金", "土", "日") # RGB色の定義 COLORS = { "赤": (255, 0, 0), "緑": (0, 255, 0), "青": (0, 0, 255), "白": (255, 255, 255), "黒": (0, 0, 0) } # 今日は何曜日? day_index = 2 # 水曜日 print(f"今日は{WEEKDAYS[day_index]}曜日です") # 色の取得 color = COLORS["赤"] r, g, b = color print(f"赤色のRGB: R={r}, G={g}, B={b}")
実行結果:
今日は水曜日です
赤色のRGB: R=255, G=0, B=0
2. 関数の複数戻り値
機能: 関数から複数の値をまとめて返します。
書き方:
Pythondef 関数(): return 値1, 値2, 値3
用途: 計算結果の複数値、統計値、座標計算
注意点: 戻り値が多すぎると読みにくい(3-4個まで)
Pythondef calculate_rectangle(width, height): """長方形の面積と周囲の長さを計算""" area = width * height perimeter = 2 * (width + height) return area, perimeter # 使用例 w, h = 5, 3 area, perimeter = calculate_rectangle(w, h) print(f"幅{w}, 高さ{h}の長方形") print(f" 面積: {area}") print(f" 周囲: {perimeter}") # 統計値を返す def get_statistics(numbers): return min(numbers), max(numbers), sum(numbers) / len(numbers) data = [85, 92, 78, 95, 88] min_val, max_val, avg = get_statistics(data) print(f"\n統計:") print(f" 最小: {min_val}") print(f" 最大: {max_val}") print(f" 平均: {avg:.2f}")
実行結果:
幅5, 高さ3の長方形
面積: 15
周囲: 16
統計:
最小: 78
最大: 95
平均: 87.60
3. 辞書のキー
機能: タプルは辞書のキーとして使えます(リストは不可)。
書き方:
Python辞書 = {(キー1, キー2): 値}
用途: 2次元座標のマッピング、複合キー
注意点: タプル内の要素もイミュータブルである必要がある
Python# 座標をキーにした地図 world_map = { (0, 0): "スタート地点", (1, 0): "森", (2, 0): "村", (0, 1): "山", (1, 1): "湖", (2, 1): "城" } # 座標で検索 position = (1, 1) print(f"座標{position}: {world_map[position]}") # 全体を表示 print("\n=== 地図 ===") for (x, y), location in world_map.items(): print(f"({x},{y}): {location}") # 複合キーの例(姓・名) phonebook = { ("山田", "太郎"): "090-1234-5678", ("佐藤", "花子"): "090-2345-6789", ("山田", "花子"): "090-3456-7890" } name = ("山田", "太郎") print(f"\n{name[0]} {name[1]}さんの電話番号: {phonebook[name]}")
実行結果:
座標(1, 1): 湖
=== 地図 ===
(0,0): スタート地点
(1,0): 森
(2,0): 村
(0,1): 山
(1,1): 湖
(2,1): 城
山田 太郎さんの電話番号: 090-1234-5678
4. データベースのレコード
Python# データベースから取得したレコード(タプルで表現) users = [ (1, "yamada", "yamada@example.com", 28), (2, "tanaka", "tanaka@example.com", 35), (3, "sato", "sato@example.com", 42) ] print("=== ユーザー一覧 ===") for user in users: id, username, email, age = user print(f"ID:{id} {username} ({age}歳) - {email}") # 特定条件の検索 print("\n30歳以上:") for user in users: id, username, email, age = user if age >= 30: print(f" {username} ({age}歳)")
実行結果:
=== ユーザー一覧 ===
ID:1 yamada (28歳) - yamada@example.com
ID:2 tanaka (35歳) - tanaka@example.com
ID:3 sato (42歳) - sato@example.com
30歳以上:
tanaka (35歳)
sato (42歳)
5. 一時的なデータのグループ化
Python# CSVファイルの行データ csv_data = [ ("商品A", 1000, 10), ("商品B", 1500, 5), ("商品C", 800, 20) ] print("=== 在庫一覧 ===") total_value = 0 for row in csv_data: name, price, quantity = row value = price * quantity total_value += value print(f"{name}: {price}円 × {quantity}個 = {value}円") print(f"\n在庫総額: {total_value}円")
実行結果:
=== 在庫一覧 ===
商品A: 1000円 × 10個 = 10000円
商品B: 1500円 × 5個 = 7500円
商品C: 800円 × 20個 = 16000円
在庫総額: 33500円
5. リストとの使い分け
タプルを使うべき場合
Python# ケース1: データが変更されない MONTHS = ("1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月") # ケース2: 関数の戻り値 def get_min_max(numbers): return min(numbers), max(numbers) # ケース3: 辞書のキー cache = { ("add", 1, 2): 3, ("mul", 3, 4): 12 } # ケース4: 構造化データ person = ("太郎", 25, "東京")
リストを使うべき場合
Python# ケース1: データが変更される shopping_cart = ["りんご", "バナナ"] shopping_cart.append("オレンジ") # 追加 # ケース2: 同じ種類のデータの集まり scores = [85, 92, 78, 95] scores.sort() # ソート # ケース3: 要素の追加・削除が頻繁 todo_list = ["メール確認", "資料作成"] todo_list.remove("メール確認") # 完了 # ケース4: 同じ型の繰り返しデータ temperatures = [22.5, 23.1, 24.0, 23.8]
6. namedtupleの活用
namedtupleとは
機能: 名前付きフィールドを持つタプルのサブクラスを作成します。
書き方:
Pythonfrom collections import namedtuple クラス名 = namedtuple('クラス名', ['フィールド1', 'フィールド2'])
用途: 構造化データ、読みやすいコード、軽量なクラス
注意点: イミュータブル、メソッドは追加できない
Pythonfrom collections import namedtuple # Pointクラスの定義 Point = namedtuple('Point', ['x', 'y']) # インスタンスの作成 p1 = Point(10, 20) p2 = Point(x=30, y=40) # アクセス方法 print(f"p1: x={p1.x}, y={p1.y}") print(f"p2: x={p2.x}, y={p2.y}") # インデックスでもアクセス可能 print(f"p1[0]={p1[0]}, p1[1]={p1[1]}") # アンパックも可能 x, y = p1 print(f"アンパック: x={x}, y={y}")
実行結果:
p1: x=10, y=20
p2: x=30, y=40
p1[0]=10, p1[1]=11
アンパック: x=10, y=20
namedtupleの実用例
Pythonfrom collections import namedtuple # 社員データ Employee = namedtuple('Employee', ['id', 'name', 'department', 'salary']) employees = [ Employee(1, "山田太郎", "営業", 400000), Employee(2, "佐藤花子", "開発", 450000), Employee(3, "鈴木一郎", "人事", 380000) ] print("=== 社員リスト ===") for emp in employees: print(f"ID:{emp.id} {emp.name} ({emp.department}) - {emp.salary:,}円") # 部署でグループ化 departments = {} for emp in employees: if emp.department not in departments: departments[emp.department] = [] departments[emp.department].append(emp) print("\n=== 部署別 ===") for dept, members in departments.items(): print(f"{dept}部:") for emp in members: print(f" {emp.name}")
実行結果:
=== 社員リスト ===
ID:1 山田太郎 (営業) - 400,000円
ID:2 佐藤花子 (開発) - 450,000円
ID:3 鈴木一郎 (人事) - 380,000円
=== 部署別 ===
営業部:
山田太郎
開発部:
佐藤花子
人事部:
鈴木一郎
7. 具体例
例1: ゲームの座標管理
Python# プレイヤーの位置 player_pos = (5, 3) enemy_positions = [(2, 1), (8, 4), (6, 7)] # 距離計算 def manhattan_distance(pos1, pos2): x1, y1 = pos1 x2, y2 = pos2 return abs(x1 - x2) + abs(y1 - y2) print(f"プレイヤー位置: {player_pos}") print("\n敵との距離:") for i, enemy_pos in enumerate(enemy_positions, 1): dist = manhattan_distance(player_pos, enemy_pos) print(f" 敵{i} {enemy_pos}: 距離{dist}")
実行結果:
プレイヤー位置: (5, 3)
敵との距離:
敵1 (2, 1): 距離5
敵2 (8, 4): 距離4
敵3 (6, 7): 距離5
例2: 設定ファイルの管理
Python# アプリケーション設定 class Config: # データベース設定 DATABASE = ("localhost", 5432, "myapp", "user", "password") # サーバー設定 SERVER = ("0.0.0.0", 8000, True) # host, port, debug # ログ設定 LOG_LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR") # 設定の使用 db_host, db_port, db_name, db_user, db_pass = Config.DATABASE print(f"データベース接続: {db_user}@{db_host}:{db_port}/{db_name}") server_host, server_port, debug = Config.SERVER mode = "デバッグ" if debug else "本番" print(f"サーバー: {server_host}:{server_port} ({mode}モード)")
実行結果:
データベース接続: user@localhost:5432/myapp
サーバー: 0.0.0.0:8000 (デバッグモード)
例3: 状態遷移の定義
Python# 状態遷移テーブル(現在の状態、入力、次の状態) transitions = [ ("待機", "スタート", "実行中"), ("実行中", "一時停止", "一時停止中"), ("一時停止中", "再開", "実行中"), ("実行中", "完了", "完了"), ("一時停止中", "キャンセル", "待機") ] def get_next_state(current, action): for curr, act, next in transitions: if curr == current and act == action: return next return None # 状態遷移のシミュレーション state = "待機" actions = ["スタート", "一時停止", "再開", "完了"] print(f"初期状態: {state}") for action in actions: next_state = get_next_state(state, action) if next_state: print(f"{action} → {next_state}") state = next_state else: print(f"{action} → 無効な操作")
実行結果:
初期状態: 待機
スタート → 実行中
一時停止 → 一時停止中
再開 → 実行中
完了 → 完了
8. まとめ
このレッスンでは、タプルの実践的な活用方法を学びました。
- 座標・設定値・複数戻り値など、固定データの表現に使えると理解しました。
- タプルを使うことで、値の不意な変更を防げます。
- 分割代入と組み合わせると、読みやすく扱いやすいコードになります。
- namedtupleのような拡張的な使い方の入口を確認しました。
- データの性質に合わせて型を選ぶことの重要性を理解しました。
タプルの使い所
目次
1. このレッスンで学ぶこと
- タプルが適している場面
- リストとの使い分け
- タプルの実践的な活用方法
- namedtupleの紹介
2. タプルとは
タプルは、複数の値を順序付きで格納する、変更不可能(イミュータブル)なデータ構造です。
| 項目 | 説明 |
|---|---|
| 書き方 | (要素1, 要素2, 要素3, ...) |
| 変更 | 不可能 |
| 順序 | あり |
| 用途 | 固定データ、複数戻り値、辞書のキー |
主な特徴:
- 丸括弧
()で囲んで作成される - 一度作成すると変更できない(イミュータブル)
- インデックスとスライスでアクセス可能
- 辞書のキーとして使用できる(リストは不可)
簡単なコード例:
Python# 固定データの定義 RGB_RED = (255, 0, 0) RGB_GREEN = (0, 255, 0) print(f"赤: {RGB_RED}") print(f"第1要素: {RGB_RED[0]}") # 複数戻り値 def get_dimensions(): return 640, 480 # タプルで返される width, height = get_dimensions() print(f"画面サイズ: {width}x{height}")
3. なぜタプルを使うのか?
タプルには変更不可という特性があり、特定の状況で非常に有用です。
Python# 座標は変更されるべきでない ORIGIN = (0, 0) # RGB色は固定値 RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) # 設定値は保護したい DATABASE_CONFIG = ("localhost", 5432, "mydb", "user")
タプルを使うことで、データの整合性を保てます。
💡 豆知識: Pythonの内部では、タプルはリストよりも効率的に実装されています。ハッシュ可能なので辞書のキーにでき、メモリ使用量も少なくて済みます。
4. タプルが適している場面
1. 固定データ・定数
機能: 変更されるべきでないデータを保護します。
書き方:
Python定数 = (値1, 値2, ...)
用途: 設定値、座標、RGB色、曜日
注意点: 大文字の変数名を使うと定数であることが明確
Python# 曜日(変更されない) WEEKDAYS = ("月", "火", "水", "木", "金", "土", "日") # RGB色の定義 COLORS = { "赤": (255, 0, 0), "緑": (0, 255, 0), "青": (0, 0, 255), "白": (255, 255, 255), "黒": (0, 0, 0) } # 今日は何曜日? day_index = 2 # 水曜日 print(f"今日は{WEEKDAYS[day_index]}曜日です") # 色の取得 color = COLORS["赤"] r, g, b = color print(f"赤色のRGB: R={r}, G={g}, B={b}")
実行結果:
今日は水曜日です
赤色のRGB: R=255, G=0, B=0
2. 関数の複数戻り値
機能: 関数から複数の値をまとめて返します。
書き方:
Pythondef 関数(): return 値1, 値2, 値3
用途: 計算結果の複数値、統計値、座標計算
注意点: 戻り値が多すぎると読みにくい(3-4個まで)
Pythondef calculate_rectangle(width, height): """長方形の面積と周囲の長さを計算""" area = width * height perimeter = 2 * (width + height) return area, perimeter # 使用例 w, h = 5, 3 area, perimeter = calculate_rectangle(w, h) print(f"幅{w}, 高さ{h}の長方形") print(f" 面積: {area}") print(f" 周囲: {perimeter}") # 統計値を返す def get_statistics(numbers): return min(numbers), max(numbers), sum(numbers) / len(numbers) data = [85, 92, 78, 95, 88] min_val, max_val, avg = get_statistics(data) print(f"\n統計:") print(f" 最小: {min_val}") print(f" 最大: {max_val}") print(f" 平均: {avg:.2f}")
実行結果:
幅5, 高さ3の長方形
面積: 15
周囲: 16
統計:
最小: 78
最大: 95
平均: 87.60
3. 辞書のキー
機能: タプルは辞書のキーとして使えます(リストは不可)。
書き方:
Python辞書 = {(キー1, キー2): 値}
用途: 2次元座標のマッピング、複合キー
注意点: タプル内の要素もイミュータブルである必要がある
Python# 座標をキーにした地図 world_map = { (0, 0): "スタート地点", (1, 0): "森", (2, 0): "村", (0, 1): "山", (1, 1): "湖", (2, 1): "城" } # 座標で検索 position = (1, 1) print(f"座標{position}: {world_map[position]}") # 全体を表示 print("\n=== 地図 ===") for (x, y), location in world_map.items(): print(f"({x},{y}): {location}") # 複合キーの例(姓・名) phonebook = { ("山田", "太郎"): "090-1234-5678", ("佐藤", "花子"): "090-2345-6789", ("山田", "花子"): "090-3456-7890" } name = ("山田", "太郎") print(f"\n{name[0]} {name[1]}さんの電話番号: {phonebook[name]}")
実行結果:
座標(1, 1): 湖
=== 地図 ===
(0,0): スタート地点
(1,0): 森
(2,0): 村
(0,1): 山
(1,1): 湖
(2,1): 城
山田 太郎さんの電話番号: 090-1234-5678
4. データベースのレコード
Python# データベースから取得したレコード(タプルで表現) users = [ (1, "yamada", "yamada@example.com", 28), (2, "tanaka", "tanaka@example.com", 35), (3, "sato", "sato@example.com", 42) ] print("=== ユーザー一覧 ===") for user in users: id, username, email, age = user print(f"ID:{id} {username} ({age}歳) - {email}") # 特定条件の検索 print("\n30歳以上:") for user in users: id, username, email, age = user if age >= 30: print(f" {username} ({age}歳)")
実行結果:
=== ユーザー一覧 ===
ID:1 yamada (28歳) - yamada@example.com
ID:2 tanaka (35歳) - tanaka@example.com
ID:3 sato (42歳) - sato@example.com
30歳以上:
tanaka (35歳)
sato (42歳)
5. 一時的なデータのグループ化
Python# CSVファイルの行データ csv_data = [ ("商品A", 1000, 10), ("商品B", 1500, 5), ("商品C", 800, 20) ] print("=== 在庫一覧 ===") total_value = 0 for row in csv_data: name, price, quantity = row value = price * quantity total_value += value print(f"{name}: {price}円 × {quantity}個 = {value}円") print(f"\n在庫総額: {total_value}円")
実行結果:
=== 在庫一覧 ===
商品A: 1000円 × 10個 = 10000円
商品B: 1500円 × 5個 = 7500円
商品C: 800円 × 20個 = 16000円
在庫総額: 33500円
5. リストとの使い分け
タプルを使うべき場合
Python# ケース1: データが変更されない MONTHS = ("1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月") # ケース2: 関数の戻り値 def get_min_max(numbers): return min(numbers), max(numbers) # ケース3: 辞書のキー cache = { ("add", 1, 2): 3, ("mul", 3, 4): 12 } # ケース4: 構造化データ person = ("太郎", 25, "東京")
リストを使うべき場合
Python# ケース1: データが変更される shopping_cart = ["りんご", "バナナ"] shopping_cart.append("オレンジ") # 追加 # ケース2: 同じ種類のデータの集まり scores = [85, 92, 78, 95] scores.sort() # ソート # ケース3: 要素の追加・削除が頻繁 todo_list = ["メール確認", "資料作成"] todo_list.remove("メール確認") # 完了 # ケース4: 同じ型の繰り返しデータ temperatures = [22.5, 23.1, 24.0, 23.8]
6. namedtupleの活用
namedtupleとは
機能: 名前付きフィールドを持つタプルのサブクラスを作成します。
書き方:
Pythonfrom collections import namedtuple クラス名 = namedtuple('クラス名', ['フィールド1', 'フィールド2'])
用途: 構造化データ、読みやすいコード、軽量なクラス
注意点: イミュータブル、メソッドは追加できない
Pythonfrom collections import namedtuple # Pointクラスの定義 Point = namedtuple('Point', ['x', 'y']) # インスタンスの作成 p1 = Point(10, 20) p2 = Point(x=30, y=40) # アクセス方法 print(f"p1: x={p1.x}, y={p1.y}") print(f"p2: x={p2.x}, y={p2.y}") # インデックスでもアクセス可能 print(f"p1[0]={p1[0]}, p1[1]={p1[1]}") # アンパックも可能 x, y = p1 print(f"アンパック: x={x}, y={y}")
実行結果:
p1: x=10, y=20
p2: x=30, y=40
p1[0]=10, p1[1]=11
アンパック: x=10, y=20
namedtupleの実用例
Pythonfrom collections import namedtuple # 社員データ Employee = namedtuple('Employee', ['id', 'name', 'department', 'salary']) employees = [ Employee(1, "山田太郎", "営業", 400000), Employee(2, "佐藤花子", "開発", 450000), Employee(3, "鈴木一郎", "人事", 380000) ] print("=== 社員リスト ===") for emp in employees: print(f"ID:{emp.id} {emp.name} ({emp.department}) - {emp.salary:,}円") # 部署でグループ化 departments = {} for emp in employees: if emp.department not in departments: departments[emp.department] = [] departments[emp.department].append(emp) print("\n=== 部署別 ===") for dept, members in departments.items(): print(f"{dept}部:") for emp in members: print(f" {emp.name}")
実行結果:
=== 社員リスト ===
ID:1 山田太郎 (営業) - 400,000円
ID:2 佐藤花子 (開発) - 450,000円
ID:3 鈴木一郎 (人事) - 380,000円
=== 部署別 ===
営業部:
山田太郎
開発部:
佐藤花子
人事部:
鈴木一郎
7. 具体例
例1: ゲームの座標管理
Python# プレイヤーの位置 player_pos = (5, 3) enemy_positions = [(2, 1), (8, 4), (6, 7)] # 距離計算 def manhattan_distance(pos1, pos2): x1, y1 = pos1 x2, y2 = pos2 return abs(x1 - x2) + abs(y1 - y2) print(f"プレイヤー位置: {player_pos}") print("\n敵との距離:") for i, enemy_pos in enumerate(enemy_positions, 1): dist = manhattan_distance(player_pos, enemy_pos) print(f" 敵{i} {enemy_pos}: 距離{dist}")
実行結果:
プレイヤー位置: (5, 3)
敵との距離:
敵1 (2, 1): 距離5
敵2 (8, 4): 距離4
敵3 (6, 7): 距離5
例2: 設定ファイルの管理
Python# アプリケーション設定 class Config: # データベース設定 DATABASE = ("localhost", 5432, "myapp", "user", "password") # サーバー設定 SERVER = ("0.0.0.0", 8000, True) # host, port, debug # ログ設定 LOG_LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR") # 設定の使用 db_host, db_port, db_name, db_user, db_pass = Config.DATABASE print(f"データベース接続: {db_user}@{db_host}:{db_port}/{db_name}") server_host, server_port, debug = Config.SERVER mode = "デバッグ" if debug else "本番" print(f"サーバー: {server_host}:{server_port} ({mode}モード)")
実行結果:
データベース接続: user@localhost:5432/myapp
サーバー: 0.0.0.0:8000 (デバッグモード)
例3: 状態遷移の定義
Python# 状態遷移テーブル(現在の状態、入力、次の状態) transitions = [ ("待機", "スタート", "実行中"), ("実行中", "一時停止", "一時停止中"), ("一時停止中", "再開", "実行中"), ("実行中", "完了", "完了"), ("一時停止中", "キャンセル", "待機") ] def get_next_state(current, action): for curr, act, next in transitions: if curr == current and act == action: return next return None # 状態遷移のシミュレーション state = "待機" actions = ["スタート", "一時停止", "再開", "完了"] print(f"初期状態: {state}") for action in actions: next_state = get_next_state(state, action) if next_state: print(f"{action} → {next_state}") state = next_state else: print(f"{action} → 無効な操作")
実行結果:
初期状態: 待機
スタート → 実行中
一時停止 → 一時停止中
再開 → 実行中
完了 → 完了
8. まとめ
このレッスンでは、タプルの実践的な活用方法を学びました。
- 座標・設定値・複数戻り値など、固定データの表現に使えると理解しました。
- タプルを使うことで、値の不意な変更を防げます。
- 分割代入と組み合わせると、読みやすく扱いやすいコードになります。
- namedtupleのような拡張的な使い方の入口を確認しました。
- データの性質に合わせて型を選ぶことの重要性を理解しました。