Pythonのリストは、複数の値を順序付きで扱える便利な入れ物です。
本記事では、初心者の方がつまずきやすい「リストの要素の追加・変更・削除」を、動くサンプルとともに段階的に解説します。
値の取得は確認用として最小限に扱い、その後にappend
やinsert
、remove
、pop
、del
の違いと使い分けを丁寧に説明します。
Pythonのリスト操作の基本
まずはインデックス(位置)を使った基本操作を軽く確認します。
ここでは値の取得のみ簡単に扱います。
# リストの作成と要素の取り出し
colors = ["red", "green", "blue", "yellow"]
print(colors[0]) # 先頭(0番目)の要素を取得
print(colors[2]) # 3番目の要素を取得
print(colors[-1]) # 末尾の要素を取得(負のインデックス)
print(colors[-2]) # 末尾の1つ前の要素を取得
red
blue
yellow
blue
インデックスの数え方は0から
Pythonのリストは、先頭の要素がインデックス0、次が1というように数えます。
負のインデックスは末尾から数えます。
以下はインデックスと要素の対応イメージです。
要素 | 正のインデックス | 負のインデックス |
---|---|---|
apple | 0 | -4 |
banana | 1 | -3 |
cherry | 2 | -2 |
date | 3 | -1 |
正のインデックスで左から、負のインデックスで右から位置づけると覚えると理解がスムーズです。
範囲外アクセスはIndexError
存在しない位置にアクセスすると、IndexError
が発生します。
エラーが出たときは、インデックスの値とリストの長さを落ち着いて確認しましょう。
nums = [10, 20, 30]
try:
print(nums[3]) # 長さ3のリストに対してインデックス3は範囲外
except IndexError as e:
# エラー内容をわかりやすく表示
print(type(e).__name__ + ":", e)
IndexError: list index out of range
リストに要素を追加する(append/insert)
要素の追加には主にappend
とinsert
を使います。
append
は末尾に、insert
は任意の位置に新しい要素を挿入します。
appendで末尾に追加
append
は最もよく使う追加方法で、リストの末尾に1つの要素を加えます。
戻り値はNone
なので、式の結果として代入しない点に注意します。
a = [1, 2]
a.append(3) # 末尾に3を追加
print(a) # [1, 2, 3]
ret = a.append(4) # appendの戻り値はNone。a自体が直接更新される
print(a) # [1, 2, 3, 4]
print(ret) # None
[1, 2, 3]
[1, 2, 3, 4]
None
よくある落とし穴
a = a.append(x)
としてしまうと、a
にNone
が代入されてしまいます。
append
は「その場でリストを更新する」メソッドです。
a.append(x)
とだけ書いてください。
insertで位置を指定して挿入
insert(i, x)
は、インデックスi
の位置に値x
を挿入します。
指定した位置「の前」に入るとイメージすると理解しやすいです。
i
が負の場合は末尾側からの位置として解釈され、範囲外でもエラーにはならず、先頭または末尾に挿入されます。
letters = ["A", "C"]
letters.insert(1, "B") # インデックス1の位置に「B」を挿入
print(letters) # ["A", "B", "C"]
letters.insert(0, "Start") # 先頭に挿入
print(letters) # ["Start", "A", "B", "C"]
letters.insert(100, "End") # 末尾より右に挿入しようとすると末尾に入る
print(letters) # ["Start", "A", "B", "C", "End"]
letters.insert(-1, "X") # -1は「末尾の手前」の位置を指す
print(letters) # ["Start", "A", "B", "C", "X", "End"]
['A', 'B', 'C']
['Start', 'A', 'B', 'C']
['Start', 'A', 'B', 'C', 'End']
['Start', 'A', 'B', 'C', 'X', 'End']
appendとinsertの使い分け
単純に「最後に足していく」のであればappend
が最適です。
append
は平均的に高速(O(1)相当)で、ログを積み上げる、スタックのように使うなどの用途に向きます。
一方で、特定の位置に差し込みたい場合はinsert
を使います。
ただしinsert
はリストをシフトするため要素数に比例して処理が重くなります(O(n))。
大量データで頻繁に先頭に挿入する用途には不向きで、その場合はcollections.deque
などの別構造も検討すると良いです。
リストの要素を変更する
既存の要素を別の値に置き換えるには、インデックス代入を使います。
インデックス代入で要素を変更
任意の位置を指定して、そこに新しい値を代入します。
負のインデックスも利用できます。
colors = ["red", "green", "blue"]
colors[1] = "emerald" # 2番目を別の値に置き換え
print(colors)
colors[-1] = "navy" # 末尾を置き換え
print(colors)
['red', 'emerald', 'blue']
['red', 'emerald', 'navy']
補足: まとめて置き換えるならスライス代入
本記事の主題から一歩踏み込みますが、colors[0:2] = ["pink", "cyan"]
のようにスライス代入を使うと、範囲まとめての置き換えや要素数の増減も可能です。
個別のappend
/insert
を繰り返すよりも簡潔になる場面があります。
存在しない位置は変更できない
リストの長さを超える位置への代入はできず、IndexError
が発生します。
新しい位置に値を「追加」したいなら、append
やinsert
を使います。
nums = [10, 20, 30]
try:
nums[5] = 999 # 長さ3のリストに対してインデックス5は存在しない
except IndexError as e:
print(type(e).__name__ + ":", e)
# 追加したい場合はappendやinsertを使う
nums.append(40) # 末尾に追加
nums.insert(1, 15) # 2番目の位置に挿入
print(nums)
IndexError: list assignment index out of range
[10, 15, 20, 30, 40]
リストの要素を削除する(remove/pop/del)
削除は主に3通りあります。
値で指定して削除したいときはremove
、取り出しつつ削除したいときはpop
、位置や範囲を無言で消したいときはdel
を使います。
removeで値に一致する要素を削除
remove(x)
は、最初に見つかったx
だけを削除します。
同じ値が複数あっても1つだけが対象です。
存在しない値を指定するとValueError
になります。
names = ["Alice", "Bob", "Alice", "Carol"]
names.remove("Alice") # 最初の"Alice"だけが削除される
print(names)
try:
names.remove("Dave") # 存在しない値をremoveするとエラー
except ValueError as e:
print(type(e).__name__ + ":", e)
# すべての"Alice"を削除したい場合の一例
names = ["Alice", "Bob", "Alice", "Carol"]
while "Alice" in names:
names.remove("Alice")
print(names)
['Bob', 'Alice', 'Carol']
ValueError: list.remove(x): x not in list
['Bob', 'Carol']
removeの使いどころ
値の存在が確実、かつ最初に見つかった1件だけを消したいときに向きます。
存在が不確実な場合は、事前にif x in lst:
で確認すると安全です。
popで末尾や指定位置を取り出して削除
pop()
は要素を削除すると同時に、その値を戻り値として返します。
インデックスを省略すると末尾、指定すればその位置の要素を取り出します。
空のリストに対してpop()
する、または範囲外の位置を指定するとIndexError
です。
stack = [1, 2, 3]
last = stack.pop() # 末尾を取り出して削除
print(last, stack) # 3 [1, 2]
first = stack.pop(0) # 先頭を取り出して削除(キュー的な動作)
print(first, stack) # 1 [2]
try:
empty = [].pop() # 空のリストからは取り出せない
except IndexError as e:
print(type(e).__name__ + ":", e)
3 [1, 2]
1 [2]
IndexError: pop from empty list
popの使いどころ
取り出した値を直後に使いたいときに最適です。
スタック(LIFO)ならpop()
とappend()
、キュー(FIFO)ならpop(0)
とappend()
で実現できます。
ただしpop(0)
は要素のシフトが起きるため大きなリストでは遅くなります。
delで指定位置を削除
del
文は、位置や範囲を指定して削除します。
戻り値はありません。
スライスを使えば範囲削除も簡単です。
nums = [10, 20, 30, 40, 50]
del nums[1] # インデックス1の要素(20)を削除
print(nums)
# delは戻り値を返しません。値も必要ならpopを使う
del nums[-1] # 末尾(50)を削除
print(nums)
# 応用: スライスで範囲削除
nums = [10, 20, 30, 40, 50]
del nums[1:4] # 20, 30, 40を削除
print(nums)
[10, 30, 40, 50]
[10, 30, 40]
[10, 50]
remove/pop/delの違いを一覧で整理
以下に、よく使う削除系の挙動を比較します。
メソッド/文 | 指定の仕方 | 作用対象 | 戻り値 | 例外が出る条件 | 一言メモ |
---|---|---|---|---|---|
append(x) | 末尾に追加 | 追加 | None | ほぼなし | 追加専用。高速でシンプル |
insert(i, x) | 位置iに挿入 | 追加 | None | ほぼなし | 任意位置に差し込み。大きいリストでは重くなる |
remove(x) | 値x | 最初に一致した要素を削除 | なし | 値が存在しない(ValueError) | 値で消したいときに |
pop([i]) | 省略時は末尾、指定時は位置i | 指定要素を削除して取り出す | 取り出した値 | 空や範囲外(IndexError) | 値も使いたいときに |
del obj[i] / del obj[slice] | 位置やスライス | 指定要素や範囲を削除 | なし | 範囲外(IndexError) | 範囲削除や複数削除に便利 |
まとめ
本記事では、リストの要素を追加・変更・削除するための基本操作を、動作とエラー挙動を含めて解説しました。
末尾に足すならappend
、位置を指定して挿入するならinsert
、値で消すならremove
、値を取り出しながら消すならpop
、位置や範囲を無言で消すならdel
と覚えるとすっきり整理できます。
存在しない位置へのアクセスや代入はIndexError
、remove
で見つからなければValueError
になる点にも注意してください。
まずは小さなリストで手を動かし、挙動を体で覚えることが上達への近道です。