Pythonのリストは、学習の早い段階で必ず使う基礎データ構造です。
- 関連記事:リスト(list)の使い方
この記事では要素の追加(append/insert)、変更(インデックス/スライス代入)、削除(remove/pop/del)を順番に整理し、初心者の方でも迷わないように実行例と注意点を丁寧に説明します。
実務でつまずきがちな参照や例外も押さえます。
リストに要素を追加する(append/insert)
appendで末尾に追加
最もよく使う追加方法がappend
です。
リストの末尾に1要素だけを追加します。
# 末尾に要素を追加する append の基本
fruits = ["apple", "banana"]
fruits.append("cherry") # 末尾に1要素追加
print(fruits)
# append は「1つの要素」を追加する点に注意
nums = [1, 2]
nums.append([3, 4]) # リストをそのまま1要素として追加(ネストされる)
print(nums)
['apple', 'banana', 'cherry']
[1, 2, [3, 4]]
ポイントとして、append
は配列を「展開」せず、そのものを1要素として末尾に入れます。
- 関連記事:リストを昇順・降順にソートする
insertで任意の位置に追加
insert(index, value)
は、指定位置に新しい要素を挿入します。
既存の要素は右へシフトします。
# 任意の位置に追加する insert の基本
letters = ["a", "c", "d"]
letters.insert(1, "b") # インデックス1の位置に'b'を挿入
print(letters)
# 先頭や末尾付近、負のインデックスの例
letters.insert(0, "start") # 先頭に挿入
letters.insert(len(letters), "end") # 末尾に挿入(appendと同じ結果)
letters.insert(-1, "X") # 末尾の1つ手前に挿入
print(letters)
# 範囲外のインデックスは丸められる
nums = [10, 20]
nums.insert(100, 99) # 末尾に追加される
nums.insert(-100, 0) # 先頭に追加される
print(nums)
['a', 'b', 'd', 'c']
['start', 'a', 'b', 'd', 'X', 'c', 'end']
[0, 10, 20, 99]
appendとinsertの使い分け
基本はappend
で末尾に積み上げ、順番を制御したいときや途中に挟みたいときだけinsert
を使います。
パフォーマンス面では、リストの途中に入れるinsert
は要素のシフトを伴うため、大きなリストで頻繁に行うと遅くなる点に注意します。
末尾追記が中心ならappend
が高速です。
以下に比較を簡単にまとめます。
メソッド | 追加位置 | 速度の目安 | 主用途 |
---|---|---|---|
append(x) | 末尾のみ | 速い | ログや結果の順次蓄積 |
insert(i, x) | 任意の位置 | 遅くなりやすい | 並び順の制御、見出しの挿入 |
追加時の注意点(ネスト/参照)
リストはミュータブル(変更可能)なオブジェクトで、参照が共有されることを意識する必要があります。
まず、append
でリストを追加するとネストになります。
加えて、同じインナ−リストを複数箇所で参照すると、1箇所の更新が他方にも影響します。
# 同じリストオブジェクトを2回追加した場合の参照の共有
row = [0, 0]
grid = []
grid.append(row) # 同じオブジェクトへの参照を追加
grid.append(row) # もう一度同じ参照を追加
grid[0][0] = 1 # 片方を更新
print(grid) # 両方が変わって見える(同じ参照だから)
print(grid[0] is grid[1]) # 参照が同一かどうか
[[1, 0], [1, 0]]
True
意図せず共有された参照を避けるには、新しいリストを作るかコピーします。
# 新しいリストオブジェクトとして追加する例
grid = []
grid.append([0, 0]) # リテラルで新規作成
grid.append([0, 0]) # それぞれ別オブジェクト
grid[0][0] = 1
print(grid)
print(grid[0] is grid[1]) # 参照は別
[[1, 0], [0, 0]]
False
また、リストの掛け算での初期化も落とし穴です。
# NG: 内側のリスト参照がすべて同じになる
grid = [[0] * 3] * 2
grid[0][0] = 1
print(grid) # 2行とも変わる
# OK: 内側をループで個別に生成する
grid2 = [[0] * 3 for _ in range(2)]
grid2[0][0] = 1
print(grid2)
[[1, 0, 0], [1, 0, 0]]
[[1, 0, 0], [0, 0, 0]]
リスト要素を変更する(インデックス/スライス代入)
インデックス指定で1要素を更新
単一要素の変更はlist[index] = value
で行います。
負のインデックスは末尾から数えます。
# 1要素の更新
scores = [50, 60, 70]
scores[1] = 90 # 2番目を90に
scores[-1] = 100 # 末尾を100に
print(scores)
[50, 90, 100]
スライス代入で複数要素を置換
list[start:end:step] = iterable
という形で、複数の要素をまとめて置換できます。
置換先と置換元の要素数は同数でなくても良いため、リストの長さが変わることもあります。
# 基本: 連続範囲を別のシーケンスで置換
nums = [0, 1, 2, 3, 4, 5]
nums[1:4] = [10, 11] # 要素数が減る(1,2,3 -> 10,11)
print(nums)
# 連続範囲を挿入的に増やす
nums[2:2] = [20, 21, 22] # 空のスライス位置に挿入
print(nums)
# ステップ付きスライスは要素数を一致させる必要がある
letters = list("abcdef")
letters[::2] = ["A", "B", "C"] # 0,2,4番目を同数で置換
print(letters)
[0, 10, 11, 4, 5]
[0, 10, 20, 21, 22, 11, 4, 5]
['A', 'b', 'B', 'd', 'C', 'f']
変更時の注意点(IndexError/型の不一致)
単一インデックスでの代入は、存在しない位置を指定するとIndexErrorになります。
スライス代入は範囲外でも空の範囲として扱われるため例外にはなりにくいですが、代入値は「イテラブル」でなければTypeErrorになります。
data = [1, 2, 3]
try:
data[5] = 99 # 範囲外: IndexError
except IndexError as e:
print("IndexError:", e)
try:
data[1:2] = 100 # イテラブルではない: TypeError
except TypeError as e:
print("TypeError:", e)
# 型の不一致は文法上はOKでも、後段ロジックでバグの原因になりやすい
data[0] = "one" # 文字列に置き換え(可)
print(data)
IndexError: list assignment index out of range
TypeError: can only assign an iterable
['one', 2, 3]
型の一貫性は後の処理の前提になります。
特に数値リストの途中に文字列を混ぜると、合計や並べ替えでエラーになります。
混在させない設計を心がけます。
リスト要素を削除する(remove/pop/del)
removeで値を指定して削除
remove(value)
は最初に見つかった値だけを削除します。
該当がないとValueErrorです。
colors = ["red", "blue", "green", "blue"]
colors.remove("blue") # 最初の"blue"だけ消える
print(colors)
# 見つからないと ValueError
try:
colors.remove("yellow")
except ValueError as e:
print("ValueError:", e)
['red', 'green', 'blue']
ValueError: list.remove(x): x not in list
popで位置を指定して取り出し削除
pop(index)
は削除と同時に取り出した値を返すため、スタックやキューのような用途に適しています。
インデックス省略で末尾を扱います。
stack = [1, 2, 3]
last = stack.pop() # 末尾を取り出して削除
print(last, stack)
queue = ["a", "b", "c"]
first = queue.pop(0) # 先頭を取り出して削除(計算量に注意)
print(first, queue)
# 範囲外は IndexError
try:
queue.pop(10)
except IndexError as e:
print("IndexError:", e)
3 [1, 2]
a ['b', 'c']
IndexError: pop index out of range
delで位置や範囲を削除
del
文は、インデックスやスライスで範囲削除できます。
戻り値はありません。
nums = [0, 1, 2, 3, 4, 5, 6]
del nums[2] # 単一要素を削除
print(nums)
del nums[1:4] # 連続範囲を削除
print(nums)
del nums[::2] # パターンに一致する要素を削除(ステップ指定)
print(nums)
# 変数自体の削除にも使える(以降参照するとNameError)
temp = [9, 9]
del temp
try:
print(temp)
except NameError as e:
print("NameError:", e)
[0, 1, 3, 4, 5, 6]
[0, 4, 5, 6]
[4, 6]
NameError: name 'temp' is not defined
remove/pop/delの使い分け
値が分かっているならremove
、位置が分かっていて取り出したいならpop
、範囲でまとめて消すならdel
が基本方針です。
取り出し不要で単一位置ならdel list[i]
でも構いません。
以下に簡単な比較を示します。
操作 | 指定方法 | 戻り値 | 主な用途 | 例外 |
---|---|---|---|---|
remove(x) | 値 | なし | 値が分かっているとき | ValueError |
pop(i) | 位置(省略で末尾) | 取り出した値 | スタック/キュー | IndexError |
del | 位置/範囲/ステップ | なし | 範囲削除・大量削除 | (構文エラー以外は通常なし) |
削除時の注意点(ValueError/IndexError)
- 値が存在するか不明な場合は、削除前に
if x in list:
で存在確認を行うとValueErrorを避けられます。 - 位置で削除するときは
len(list)
と比較してIndexErrorを避けます。 - 先頭で
pop(0)
を多用するとシフトが頻発し遅くなるため、キュー用途ならcollections.deque
の利用を検討します。
items = ["a", "b", "c"]
# 存在確認してから remove
target = "x"
if target in items:
items.remove(target) # 実行されない
print(items)
# 安全な pop 例
idx = 2
if 0 <= idx < len(items):
got = items.pop(idx)
print("popped:", got)
['a', 'b', 'c']
popped: c
- 関連記事:例外(Exception)入門
- 関連記事:リストの重複を削除するsetの使い方
まとめ
本記事では、追加(append/insert)、変更(インデックス/スライス代入)、削除(remove/pop/del)の基本と注意点を体系的に解説しました。
末尾中心ならappend
、途中に入れるならinsert
、1点更新はインデックス代入、複数置換はスライス代入が有効です。
削除はremove
・pop
・del
を用途で使い分け、ValueError/IndexErrorを予防するチェックを挟むと安全です。
さらに、リストは参照型であるためネストやコピーの扱いに注意しましょう。
これらの基礎を正しく押さえることで、実用的なデータ処理がスムーズに行えるようになります。
- 関連記事:リスト vs タプル vs セットの違い