JEPA4Japan · チュートリアル

リスト、タプル、シーケンスの考え方

2,013文字 6分で読めます #Python

順序のあるデータを扱い、同一性、別名参照、変更可能性、コピー、アンパック、シーケンス演算を理解します。

コース進捗 コース目次 24レッスン中 24件を公開中

リストはトレー、タプルは封をしたカード

値が1つだけでは足りないことがあります。学習トピックをいくつも並べたり、7日分の記録を持ったり、(曜日, 分数)という1件の記録を作ったりしたいからです。Pythonには、順序のあるまとまりを作る2つの便利な形があります。

  1. リスト 中身を出し入れできる
  2. タプル 位置の役目を固定する
  3. シーケンス 順番どおりに読める
変わる集まりにはリスト、形の決まった1件の記録にはタプルを使います。

どちらもシーケンスです。要素の順序を保ち、位置は0から始まり、len()、in、インデックス、スライスを使えます。

topics = ["文字列", "リスト", "辞書"]

print(len(topics))
print(topics[0])
print(topics[-1])
print(topics[1:3])
print("リスト" in topics)
3
文字列
辞書
['リスト', '辞書']
True

スライスは終了位置の直前で止まり、新しい外側のシーケンスを作ります。存在しない1つの位置はIndexErrorですが、スライスは末尾を越えても安全です。

リストは増やしたり減らしたりできる

リストは角かっこで書き、**変更可能(mutable)**です。同じリストの中身を変えられます。

queue = ["文字列", "リスト"]
queue.append("タプル")
queue.extend(["辞書", "集合"])
queue.insert(1, "復習")

print(queue)
['文字列', '復習', 'リスト', 'タプル', '辞書', '集合']

append(x)は1つの要素を加えます。extend(things)はthings内の要素を1つずつ加えます。["A", "B"]をappendすれば、入れ子のリスト1つです。extendなら文字列2つが追加されます。

値を指定して消すならremove()、位置を指定して消し、消した値も受け取るならpop()です。

queue = ["文字列", "復習", "リスト"]
queue.remove("復習")
finished = queue.pop(0)

print(finished)
print(queue)
文字列
['リスト']

境界の注意:remove("ない値")はValueError、空リストのpop()はIndexErrorです。値がないことも普通にあるなら、先にinや空でないことを確認します。

2枚の名札が同じトレーを指すことがある

代入してもリストはコピーされません。同じトレーへ別の名札を付けるだけです。

  1. リストは1つ ["文字列", "リスト"]
  2. plan 1枚目の名札
  3. alias 2枚目の名札
  4. 変更は1回 どちらからも見える
alias = planでは、1つの変更可能なオブジェクトを共有します。
plan = ["文字列", "リスト"]
alias = plan
snapshot = plan.copy()

alias.append("タプル")

print(plan)
print(snapshot)
print(alias is plan)
print(snapshot is plan)
['文字列', 'リスト', 'タプル']
['文字列', 'リスト']
True
False

isは「まったく同じオブジェクト?」、==は「中身が等しい?」という質問です。copy()やplan[:]は、新しい外側のリストを作ります。ただし、これは浅いコピーです。入れ子の変更可能な要素は共有されます。

week = [["月", 20], ["火", 30]]
snapshot = week.copy()

week.append(["水", 40])
week[0][1] = 99

print(snapshot)
print(week)
[['月', 99], ['火', 30]]
[['月', 99], ['火', 30], ['水', 40]]

新しい水曜日のトレーはweekだけにあります。一方、2つの外側のリストは同じ月曜日の内側トレーを指し続けるため、どちらにも99が見えます。

タプルは1件の記録の形を守る

タプルは通常、丸かっこで書きます。変更不可能なシーケンスなので、append()、remove()、要素への代入はできません。

  1. 月曜日 位置0
  2. 45分 位置1
  3. 固定の組 2つの役目を保つ
各位置に変わらない役目があるとき、タプルが役立ちます。
record = ("月曜日", 45)
day, minutes = record

print(day)
print(minutes)
月曜日
45

通常のアンパックでは、要素と受け取る名前の個数を一致させます。1要素のタプルにはカンマが必要です。("リスト",)はタプル、("リスト")は文字列です。タプル自体は変わりませんが、その中に変更可能なリストがあれば、そのリストは変えられます。タプルは「内側まですべて凍らせる箱」ではありません。

ミニ制作:3日間の学習記録

study_log.pyを作ります。組み込み機能だけで動く完成プログラムです。曜日の記録は固定のタプル、記録全体とトピック待ち行列はリストです。スナップショットによって、別名ではなくコピーを作れたことも確かめます。

study_log = [
    ("月曜日", 20),
    ("火曜日", 35),
    ("水曜日", 35),
]
topic_queue = ["文字列", "リスト", "辞書"]

original_plan = topic_queue.copy()

finished = topic_queue.pop(0)
topic_queue.append("集合")

total = 0
for day, minutes in study_log:
    total += minutes
    print(f"{day}:{minutes}分")

average = total / len(study_log)

print(f"合計:{total}分")
print(f"平均:{average:.1f}分")
print(f"完了:{finished}")
print(f"最初:{original_plan}")
print(f"現在:{topic_queue}")
print(f"スナップショットは安全:{original_plan == ['文字列', 'リスト', '辞書']}")

python3 study_log.pyで実行し、次の出力を確認します。

月曜日:20分
火曜日:35分
水曜日:35分
合計:90分
平均:30.0分
完了:文字列
最初:['文字列', 'リスト', '辞書']
現在:['リスト', '辞書', '集合']
スナップショットは安全:True

このプログラムには必ず3件あるので、平均の割り算は安全です。空の記録も許すなら、割る前に「空の平均」をどうするか決める必要があります。

3つの小さなミッション

  1. appendかextendか。 ["タプル", "集合"]を両方の方法で追加し、どちらが入れ子になるか予想します。
  2. コピー探偵。 [["月", 10]]をコピーしてから、内側の10を変更します。両方から変化が見える理由を説明します。
  3. タプル調査。 (topic, minutes, done)を作り、3つの名前へアンパックして1文を表示します。

第7章へ進む準備

  • インデックスとスライスでシーケンスを読める
  • append()、extend()、remove()、pop()を使い分けられる
  • 別名参照がリストの変更を共有する理由を説明できる
  • 浅いコピーを作り、入れ子の境界を説明できる
  • 変わるリストと、形を固定するタプルを選べる
  • 1要素のタプルを作り、記録を正しくアンパックできる
  • 学習記録を実行し、「スナップショットは安全:True」を確認できる

次章では、番号の代わりに意味のある辞書のキーを使い、「同じものは1つだけ」が大切な場面で集合を使います。