リスト(list)は、Pythonでもっともよく使うデータ構造です。複数の値を順番に並べて持ち、あとから追加・削除・並び替えができます。[1, 2, 3]のように角かっこで書きます。
基本は簡単ですが、初心者がつまずきやすい罠が2つあります。要素を増やすappendとextendの違い、そしてリストをコピーしたつもりが同じものを指していて、片方を変えるともう片方も変わるという参照の問題です。この記事では、実機のPythonで確認しながら、リストの使い方を整理します。
- 作成は
[1, 2, 3]、空は[]、範囲からはlist(range(5))です。 - 取り出しは
lst[0]、末尾はlst[-1]、範囲はlst[1:3](スライス)です。 - 追加は1個なら
append、複数ならextend。appendはリストごと1要素として入る点に注意します。 - 削除は値で
remove、位置でpop・delです。 - 並び替えは元を変える
sort()、新しいリストを返すsorted()です。 - コピーは
lst[:]やlst.copy()。単純な代入は同じリストを指すだけなので注意します。
リストはループと一緒に使うことが多いので、forループで繰り返し処理を行う方法、range関数の使い方、文字列を連結・結合する方法もあわせて参考になります。
リストを作る
リストは角かっこ[ ]で作ります。文字列や範囲(range)から作ることもできます。
# 角かっこで作る
fruits = ["りんご", "みかん", "ぶどう"]
numbers = [1, 2, 3, 4, 5]
# 空のリスト
empty = []
# 文字列から(1文字ずつ)
chars = list("abc") # ['a', 'b', 'c']
# 範囲から連番を作る
seq = list(range(5)) # [0, 1, 2, 3, 4]
# 型が混ざってもよい
mixed = [1, "文字", True, 3.14]
実機でも、list(range(5))は[0, 1, 2, 3, 4]、list("abc")は['a', 'b', 'c']になりました。リストには数値・文字列・真偽値など、異なる型を混ぜて入れられます。
要素にアクセスする(インデックス・スライス)
要素はインデックス(0始まり)で取り出します。マイナスで末尾から数え、範囲で複数まとめて取り出す「スライス」も使えます。
lst = [10, 20, 30, 40, 50] lst[0] # 10(最初) lst[-1] # 50(最後) # スライス [開始:終了](終了は含まない) lst[1:3] # [20, 30] lst[:2] # [10, 20](先頭から) lst[2:] # [30, 40, 50](末尾まで) lst[::2] # [10, 30, 50](1つ飛ばし) lst[::-1] # [50, 40, 30, 20, 10](逆順)
実機でも、lst[-1]が50、lst[1:3]が[20, 30]、lst[::-1]が逆順になりました。スライスで取り出した結果は元のリストのコピーです。スライスの一部を書き換えても、元のリストには影響しません。この性質は、後半のコピーの話につながります。
要素を追加する(append / extend / insert)
要素を増やす方法は3つあります。1個追加するappend、複数追加するextend、位置を指定するinsertです。
lst = [1, 2, 3] # 末尾に1個追加 lst.append(4) # [1, 2, 3, 4] # 複数をまとめて追加(リストの中身を展開して足す) lst.extend([5, 6]) # [1, 2, 3, 4, 5, 6] # += でも同じ lst += [7] # [1, 2, 3, 4, 5, 6, 7] # 位置を指定して挿入 lst.insert(0, 99) # 先頭に99を入れる → [99, 1, 2, ...]
【重要】appendとextendの違い
appendとextendは、どちらも「足す」ですが、結果がまったく違います。appendは渡したものを「1つの要素」として末尾に入れ、extendは「中身を1つずつ」足します。
a = [1, 2] a.append([3, 4]) print(a) # [1, 2, [3, 4]] ← リストごと1要素として入る b = [1, 2] b.extend([3, 4]) print(b) # [1, 2, 3, 4] ← 中身が展開されて足される
実機で確認したところ、[1, 2].append([3, 4])は[1, 2, [3, 4]]になり、リストが丸ごと1つの要素として入りました。一方、extend([3, 4])は[1, 2, 3, 4]と、中身が1つずつ足されました。「別のリストの要素を全部足したい」ときにappendを使うと、リストがネスト(入れ子)してしまいます。中身を足すならextend(または+=)、リストごと1要素として入れたいならappend、と使い分けてください。
要素を削除する(remove / pop / del)
削除も3つあります。値で消すremove、位置で取り出しながら消すpop、位置で消すdelです。
lst = [10, 20, 30, 20] # 値で削除(最初に一致した1つだけ) lst.remove(20) # [10, 30, 20] # 位置で取り出して削除(戻り値あり) lst = [10, 20, 30] x = lst.pop() # x=30, lst=[10, 20](省略すると末尾) y = lst.pop(0) # y=10, lst=[20] # 位置で削除(戻り値なし) lst = [10, 20, 30] del lst[1] # [10, 30] # すべて削除 lst.clear() # []
実機でも、remove(20)は最初の20だけを消し、pop()は末尾を取り出して返しました。注意点として、removeで存在しない値を指定するとValueError、popで範囲外の位置を指定するとIndexErrorになります。消す前にinで存在を確認すると安全です。
検索と要素数(in / index / count / len)
値が含まれるかの判定や、位置・個数・要素数の取得です。
lst = [1, 2, 2, 3] 2 in lst # True(含まれるか) 5 not in lst # True lst.index(2) # 1(最初に2がある位置) lst.count(2) # 2(2の個数) len(lst) # 4(要素数) # 数値リストなら合計・最小・最大も sum([1, 2, 3]) # 6 min([3, 1, 2]) # 1 max([3, 1, 2]) # 3
実機でも、2 in lstがTrue、index(2)が1、count(2)が2、lenが4になりました。indexは最初に見つかった位置を返し、存在しないとValueErrorになります。
並び替える(sort / sorted / reverse)
並び替えには2種類あります。元のリストを直接並び替えるsort()と、新しい並び替え済みリストを返すsorted()です。
# sorted は新しいリストを返す(元は変わらない) nums = [3, 1, 2] result = sorted(nums) # [1, 2, 3] print(nums) # [3, 1, 2](元のまま) # sort は元のリストを並び替える(戻り値は None) nums.sort() # nums 自体が [1, 2, 3] になる nums.sort(reverse=True) # 降順 [3, 2, 1] # key で並び替えの基準を指定(文字数順など) words = ["bbb", "a", "cc"] words.sort(key=len) # ['a', 'cc', 'bbb'] # 逆順にする(並び替えではなく反転) nums.reverse()
実機で確認したところ、sorted(nums)は新しいリストを返し、元のnumsは[3, 1, 2]のまま変わりませんでした。一方、nums.sort()はnums自体を並び替えます。さらに注意したいのが、sort()の戻り値はNoneだということです。new = nums.sort()と書くと、newにはNoneが入ってしまいます。新しいリストがほしいときはsorted()を使ってください。key=lenのように基準を指定すれば、文字数順や特定の項目順にも並べられます。
【最重要】コピーと参照共有の罠
リストでもっとも注意が必要なのがこれです。b = aのような単純な代入は、リストをコピーしません。aとbは同じリストを指すため、片方を変えるともう片方も変わります。
a = [1, 2, 3] b = a # コピーではなく「同じリスト」を指す b.append(4) print(a) # [1, 2, 3, 4] ← a も変わってしまう! # 独立したコピーを作る方法 c = [1, 2, 3] d = c[:] # スライスでコピー e = c.copy() # copy() メソッド f = list(c) # list() で作り直す d.append(99) print(c) # [1, 2, 3](元は変わらない)
実機でも、b = aのあとb.append(4)するとaも[1, 2, 3, 4]になりました。独立したコピーがほしいときは、c[:]・c.copy()・list(c)のいずれかを使います。さらに、もう1つ有名な罠があります。
# NG: [[]]*3 は「同じ空リスト」を3つ並べる
grid = [[]] * 3
grid[0].append("X")
print(grid) # [['X'], ['X'], ['X']] ← 全部に入ってしまう!
# OK: 内包表記で別々のリストを作る
grid = [[] for _ in range(3)]
grid[0].append("X")
print(grid) # [['X'], [], []] ← 独立している
# 数値など変更できない値なら [0]*3 は問題ない
nums = [0] * 3 # [0, 0, 0](安全)
[[]] * 3のように「リストを含むリスト」を掛け算で作ると、実機でも同じ内側リストが3つ並ぶ結果になりました。1つに追加すると、見かけ上すべてに入ります。2次元配列のような構造を作るときは、[[] for _ in range(3)]のように内包表記で1つずつ作ってください。一方、[0] * 3のように中身が数値(変更できない値)なら、共有されても書き換えで影響しないため問題ありません。
よくある失敗
extendのつもりでappendしてネストする
別のリストの中身を足したいならextendです。appendを使うとリストが丸ごと1要素として入り、入れ子になります。
b = a でコピーしたつもりになる
単純な代入は同じリストを指すだけです。独立したコピーはa[:]・a.copy()・list(a)で作ります。
[[]]*3 で2次元リストを作る
中身が共有されてしまいます。[[] for _ in range(3)]のように内包表記で1つずつ作ります。
new = lst.sort() と書く
sort()の戻り値はNoneです。新しいリストがほしいならsorted(lst)を使います。
remove / index で存在しない値を指定する
存在しない値をremove・indexに渡すとValueErrorになります。先にinで確認すると安全です。
よくある質問
append、別のリストの中身をまとめて追加するならextendです。append([3, 4])はリストが1要素として入り[..., [3, 4]]になり、extend([3, 4])は中身が展開されて[..., 3, 4]になります。lst[:]、lst.copy()、list(lst)のいずれかを使います。単純なb = aはコピーではなく、同じリストを指すだけなので、片方を変えると両方変わります。sort()は元のリストを直接並び替え、戻り値はNoneです。sorted()は新しい並び替え済みリストを返し、元は変えません。元を残したいときや、戻り値を変数に入れたいときはsorted()を使います。[[] for _ in range(3)]のように内包表記で作ります。[[]] * 3は同じ内側リストを共有してしまい、1つに追加すると全部に入る罠があるため避けます。lst.pop()を使います。末尾の要素を返しつつ、リストから取り除きます。位置を指定すればlst.pop(0)で先頭を取り出すこともできます。まとめ
- リストは
[1, 2, 3]で作り、lst[0]・lst[-1]・スライスlst[1:3]で取り出します。 - 追加は1個なら
append、複数ならextend。appendはリストごと1要素です。 - 削除は値で
remove、位置でpop・delです。 - 並び替えは元を変える
sort()、新しく返すsorted()。sort()の戻り値はNoneです。 - コピーは
lst[:]・lst.copy()。単純な代入は同じリストを指します。 [[]]*3は中身が共有されるため、2次元は[[] for _ in range(3)]で作ります。
リストは、基本操作さえ押さえれば自在に扱えます。特に「appendとextendの違い」「単純な代入はコピーではない」「[[]]*3の共有」の3つの罠を知っておけば、初心者がハマる落とし穴をほぼ回避できます。

