Pythonの基礎 - タプルの作成と操作
概要
タプルとは、リストと同様に様々なデータの要素を格納して管理することができる。
リストと異なるのは、タプルは要素を後で追加・削除・変更することができないというのが特徴である。これをイミュータブル (不変) と呼ぶ。
タプルはイミュータブルであるため、以下に示すような特徴がある。
- ハッシュ可能であり、辞書のキーや集合の要素として使用できる。
- リストよりもメモリ効率が良い。
- 関数の戻り値として複数の値を返す際によく使用される。
- データの整合性を保証したい場合に適している。
タプルの定義
タプルを作成するには丸括弧 () を使用し、カンマで要素を区切る。
タプル名 = (要素1, 要素2, 要素3, ...)
また、空のタプルを作成するには、丸括弧 () のみで宣言する。
t1 = (1, 3, 5, 3, 7, 5)
t2 = 2, 7, 8, 3, 9, 1
t3 = ()
print(t1)
print(t2)
print(t3)
# 出力
(1, 3, 5, 3, 7, 5)
(2, 7, 8, 3, 9, 1)
()
タプルの両端の丸括弧は省略できる。(ただし、空のタプルは除く)
タプルも要素にインデックスが割り当てられている。
このインデックスを使用して、要素を抽出・スライスすることができる。
t = (10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
print(t[2])
print(t[3:8])
# 出力
30
(40, 50, 60, 70, 80)
負のインデックスを使用して、末尾から要素にアクセスすることもできる。
t = (10, 20, 30, 40, 50)
print(t[-1]) # 末尾の要素
print(t[-2]) # 末尾から2番目の要素
print(t[-3:]) # 末尾から3つの要素
# 出力
50
40
(30, 40, 50)
要素が1つだけのタプルを作成する場合、後ろにカンマを付けることでタプルと認識する。
x = (200,)
y = 300,
z = (400) # これはタプルではなく整数
print(x)
print(type(x))
print(y)
print(type(y))
print(z)
print(type(z))
# 出力
(200,)
<class 'tuple'>
(300,)
<class 'tuple'>
400
<class 'int'>
タプルのメソッドと操作
タプルのメソッド (index関数とcount関数)
タプルには、index 関数 と count 関数がある。
index 関数は、指定した要素が最初に出現するインデックスを返す。
count 関数は、指定した要素がタプル内に何回出現するかを返す。
t = (1, 2, 4, 6, 8, 5, 2, 7, 4, 4)
print(t.index(2)) # 整数値2が最初に出現するインデックス
print(t.count(4)) # 整数値4の出現回数
# 出力
1
3
index 関数は、要素が見つからない場合に、ValueError 例外を発生させる。
t = (1, 2, 3)
# t.index(99) # ValueError: tuple.index(x): x not in tuple
タプルの結合
タプルは要素の操作はできないが、タプル同士の結合を行うことができる。
以下の例では、2つのタプルのそれぞれの要素が、1つのタプルの要素として結合されている。
t1 = (1, 2, 3)
t2 = (10, 20, 30)
print(t1 + t2)
# 出力
(1, 2, 3, 10, 20, 30)
タプルの繰り返し
* 演算子を使用して、タプルの要素を繰り返すことができる。
t = (1, 2, 3)
print(t * 3)
# 出力 (1, 2, 3, 1, 2, 3, 1, 2, 3)
タプルの要素としてリストを持つ場合
タプルの要素はリストを持つことができる。
タプルの要素としてリストを変更することはできないが、リストの中の要素の変更はすることができる。
t = ([2, 4, 6], [1, 3, 5])
# t[0] = 100 # TypeError: 'tuple' object does not support item assignment
t[1][0] = 100
print(t)
# 出力 ([2, 4, 6], [100, 3, 5])
tuple関数でtuple型に変換する
tuple 関数を使用すると、他のイテラブルなデータ型からタプルを作成することができる。
# リストからタプルへの変換
lang = ["Python", "JavaScript", "Swift"]
print(tuple(lang))
# 文字列からタプルへの変換
s = "Hello"
print(tuple(s))
# rangeからタプルへの変換
r = range(5)
print(tuple(r))
# 出力
('Python', 'JavaScript', 'Swift')
('H', 'e', 'l', 'l', 'o')
(0, 1, 2, 3, 4)
組み込み関数との併用
タプルは、様々な組み込み関数と併用することができる。
len関数
len 関数は、タプルの要素数を返す。
t = (10, 20, 30, 40, 50)
print(len(t))
# 出力 5
max関数とmin関数
max 関数 と min 関数は、タプルの要素の最大値と最小値を返す。
t = (10, 50, 30, 20, 40)
print(max(t))
print(min(t))
# 出力 50 10
sum関数
sum 関数は、タプルの数値要素の合計を返す。
t = (10, 20, 30, 40, 50)
print(sum(t))
# 出力 150
sorted関数
sorted 関数は、タプルの要素をソートしたリストを返す。(タプルではなくリストが返される)
t = (30, 10, 50, 20, 40)
print(sorted(t))
print(tuple(sorted(t))) # タプルとして取得する場合
# 出力 [10, 20, 30, 40, 50] (10, 20, 30, 40, 50)
in演算子
in 演算子を使用して、タプル内に特定の要素が含まれているかを確認できる。
t = ("Python", "JavaScript", "Swift")
print("Python" in t)
print("Java" in t)
print("Java" not in t)
# 出力 True False True
タプルのアンパッキング
タプルを使用すれば、複数の変数に1文で値を渡すことができる。
以下の例では、3つの値を持ったタプルと3つの変数を用意して、タプルを代入している。
変数のそれぞれの位置とタプルの値が対応しているのが分かる。(これをタプルのアンパックと呼ぶ)
いくつでも対応させることができるが、変数が多くなると可読性が落ちる。
lang = ("Python", "JavaScript", "Swift")
Py, JS, Sw = lang
print(Py)
print(JS)
print(Sw)
# 出力 Python JavaScript Swift
アスタリスクを使用したアンパッキング
アスタリスク * を変数の前に付けることで、残りの要素をリストとして受け取ることができる。
t = (1, 2, 3, 4, 5)
first, *rest = t
print(first)
print(rest)
*start, last = t
print(start)
print(last)
first, *middle, last = t
print(first)
print(middle)
print(last)
# 出力 1 [2, 3, 4, 5] [1, 2, 3, 4] 5 1 [2, 3, 4] 5
変数の値の交換
タプルのアンパッキングを利用して、変数の値を簡単に交換することができる。
a = 10
b = 20
a, b = b, a
print(a)
print(b)
# 出力 20 10
関数の戻り値としてのタプル
関数から複数の値を返す場合、タプルがよく使用される。
def get_min_max(numbers):
return min(numbers), max(numbers)
result = get_min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(result)
min_val, max_val = get_min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(min_val)
print(max_val)
# 出力 (1, 9) 1 9
タプルの比較
タプルは辞書順 (レキシコグラフィック順序) で比較される。
最初の要素から順に比較し、異なる要素が見つかった時点で比較結果が決まる。
print((1, 2, 3) < (1, 2, 4))
print((1, 2, 3) < (1, 3, 2))
print((1, 2) < (1, 2, 0))
print((1, 2, 3) == (1, 2, 3))
# 出力 True True True True
辞書のキーとしてのタプル
タプルはイミュータブル (不変) であるため、ハッシュ可能である。
これにより、タプルは辞書のキーや集合の要素として使用することができる。
リストはミュータブルであるため、辞書のキーとして使用できない。
# タプルを辞書のキーとして使用
location = {
(35.6762, 139.6503): "Tokyo",
(40.7128, -74.0060): "New York",
(51.5074, -0.1278): "London"
}
print(location[(35.6762, 139.6503)])
# 出力 Tokyo
複数のキーを組み合わせて辞書にアクセスする場合にも便利である。
# 複合キーとしての使用例
sales = {
("2024", "Q1"): 1000,
("2024", "Q2"): 1500,
("2024", "Q3"): 1200,
("2024", "Q4"): 1800
}
print(sales["2024", "Q2"]) # 丸括弧は省略可能
# 出力 1500
ただし、タプルの要素にリスト等のミュータブルなオブジェクトが含まれている場合は、ハッシュ可能ではなくなるため、辞書のキーとして使用できない。
# タプルの要素にリストが含まれている場合
t = ([1, 2], [3, 4])
# d = {t: "value"} # TypeError: unhashable type: 'list'
名前付きタプル (namedtuple)
collections モジュールの namedtuple を使用すると、フィールド名でアクセスできるタプルを作成することができる。
通常のタプルはインデックスでしか要素にアクセスできないが、名前付きタプルは属性名でアクセスできるため、コードの可読性が向上する。
基本的な使い方
from collections import namedtuple
# 名前付きタプルの定義
Point = namedtuple('Point', ['x', 'y'])
# インスタンスの作成
p = Point(10, 20)
# フィールド名でアクセス
print(p.x)
print(p.y)
# インデックスでもアクセス可能
print(p[0])
print(p[1])
# 出力 10 20 10 20
フィールド名の指定方法
フィールド名は、リスト、タプル、またはスペース区切りの文字列で指定できる。
from collections import namedtuple
# リストで指定
Point1 = namedtuple('Point1', ['x', 'y'])
# タプルで指定
Point2 = namedtuple('Point2', ('x', 'y'))
# スペース区切りの文字列で指定
Point3 = namedtuple('Point3', 'x y')
# カンマ区切りの文字列で指定
Point4 = namedtuple('Point4', 'x, y')
名前付きタプルのメソッド
名前付きタプルには、いくつかの便利なメソッドがある。
_asdict メソッドは、名前付きタプルを辞書として返す。
from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'city'])
p = Person('Alice', 30, 'Tokyo')
print(p._asdict())
# 出力
{'name': 'Alice', 'age': 30, 'city': 'Tokyo'}
_replace メソッドは、指定したフィールドの値を置き換えた新しい名前付きタプルを返す。(元のタプルは変更されない)
from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'city'])
p1 = Person('Alice', 30, 'Tokyo')
p2 = p1._replace(age=31)
print(p1)
print(p2)
# 出力 Person(name='Alice', age=30, city='Tokyo') Person(name='Alice', age=31, city='Tokyo')
_fields 属性は、フィールド名のタプルを返す。
from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'city'])
print(Person._fields)
# 出力
('name', 'age', 'city')
typing.NamedTupleを使用した型ヒント付きの名前付きタプル
Python 3.6以降では、typing.NamedTuple を使用して、型ヒント付きの名前付きタプルを定義できる。
from typing import NamedTuple
class Point(NamedTuple):
x: float
y: float
label: str = "origin" # デフォルト値を設定可能
p = Point(1.0, 2.0)
print(p)
print(p.label)
# 出力 Point(x=1.0, y=2.0, label='origin') origin
タプルとリストの使い分け
タプルとリストは似ているが、それぞれ適した用途がある。
| 特徴 | タプル | リスト |
|---|---|---|
| 変更可能性 | イミュータブル (変更不可) | ミュータブル (変更可能) |
| メモリ効率 | より効率的 | やや非効率 |
| 辞書のキー | 使用可能 | 使用不可 |
| 用途 | 固定データ、座標、レコード | 動的なコレクション |
タプルを使用すべき場面
- データが変更されるべきではない場合
- 辞書のキーや集合の要素として使用する場合
- 関数から複数の値を返す場合
- メモリ効率が重要な場合
リストを使用すべき場面
- データの追加、削除、変更が必要な場合
- 同種のデータのコレクションを扱う場合
- 順序付きのデータを動的に操作する場合