Pythonのリスト(list)とは、複数の値を順番つきでまとめて持ち、あとから追加・削除・並べ替えができる入れ物です。 操作は、append や sort などの11個のメソッドと、len・sorted・スライスなどの組み込み関数・演算の組み合わせで書けます。

この記事では、リスト操作を「やりたいこと→コード→実行結果」の逆引き表でまとめ、全コードを Python 3.14.7(uvで導入)で実行した出力つきで解説します。さらに、x = x.sort() で None になる、[[0]*3]*3 で全行が変わる、といったつまずきやすい動きの実例と、list.insert(0, x) と deque の速度の実測、公式Wikiに基づく計算量の目安表も載せています。

Python リスト操作の早見表(逆引き)

やりたいこと コード 結果(a = [5, 3, 8, 1] など) 元を変える
末尾に1つ追加 a.append(x) None を返す する
末尾に複数追加 a.extend([x, y]) None する
位置を指定して追加 a.insert(i, x) None する
値を指定して削除 a.remove(x) 最初の1件だけ する
位置を指定して取り出す a.pop() / a.pop(i) 取り出した値 する
位置・範囲で削除 del a[i] / del a[1:3] — する
全部消す a.clear() None する
位置を探す a.index(x) 無ければ ValueError しない
個数を数える a.count(x) 整数 しない
並べ替え(元を変える) a.sort() / a.sort(reverse=True) None する
並べ替えた新しいリスト sorted(a) [1, 3, 5, 8] しない
逆順(元を変える) a.reverse() None する
逆順の新しいリスト a[::-1] / list(reversed(a)) [1, 8, 3, 5] しない
コピー a.copy() / a[:] / copy.deepcopy(a) 新しいリスト しない
要素数 len(a) 4 しない
含むか x in a / x not in a True / False しない
連結・繰り返し a + b / [0] * 3 新しいリスト しない
一部を取り出す a[1:3] / a[-1] [3, 8] / 1 しない
番号つきで回す enumerate(a, start=1) (1, 5), (2, 3)… しない
2つを組にする zip(names, prices) (名, 価格) の組 しない
最小・最大・合計 min(a) / max(a) / sum(a) 1 / 8 / 17 しない
1つでも/全部満たすか any(...) / all(...) True / False しない
変換して新しいリスト [f(x) for x in a] 内包表記 しない
重複を除く(順序維持) list(dict.fromkeys(a)) 最初の出現順 しない
N件ずつに分ける itertools.batched(a, n) タプルの組(3.12以降) しない

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Python リスト 操作 一覧|全メソッド逆引きと3.14実行結果」

リストのメソッド全11個を実行して確認

list のメソッドは append・extend・insert・remove・pop・clear・index・count・sort・reverse・copy の11個です(Python公式ドキュメント「データ構造」)。index・count・copy・pop 以外は値を返さず(None)、元のリストを直接変更します。

items = ["pen", "note"]
items.append("tape");            print(items)
items.extend(["clip", "glue"]);  print(items)
items.insert(1, "ruler");        print(items)
items.remove("note");            print(items)
last = items.pop();              print(last, items)
first = items.pop(0);            print(first, items)
print(items.index("tape"), items.count("tape"))
nums = [3, 1, 2]; nums.sort(); print(nums)
nums.sort(reverse=True); print(nums)
nums.reverse(); print(nums)
c = nums.copy(); c.append(99); print(nums, c)
nums.clear(); print(nums)
['pen', 'note', 'tape']
['pen', 'note', 'tape', 'clip', 'glue']
['pen', 'ruler', 'note', 'tape', 'clip', 'glue']
['pen', 'ruler', 'tape', 'clip', 'glue']
glue ['pen', 'ruler', 'tape', 'clip']
pen ['ruler', 'tape', 'clip']
1 1
[1, 2, 3]
[3, 2, 1]
[1, 2, 3]
[1, 2, 3] [1, 2, 3, 99]
[]
メソッド 戻り値 見つからない・空のとき
append(x) / extend(it) / insert(i, x) None —
remove(x) None ValueError
pop([i]) 取り出した値 IndexError
clear() / sort() / reverse() None —
index(x[, start[, end]]) 位置(整数) ValueError
count(x) 個数 0
copy() 浅いコピー —

append と extend の違いは、append([1, 2]) がリストを1つの要素として足すのに対し、extend([1, 2]) は中身を1つずつ足す点です。

見つからないときのエラー

["a"].remove("z")   # ValueError: list.remove(x): x not in list
["a"].index("z")    # ValueError: list.index(x): x not in list
[].pop()            # IndexError: pop from empty list
[1][5]              # IndexError: list index out of range
[1][5:9]            # [] (スライスは範囲外でもエラーにならない)
sorted([1, "a"])    # TypeError: '<' not supported between instances of 'str' and 'int'

エラーを避けたいときは、先に if x in a: で確かめてから remove や index を呼びます。

関連する組み込み関数・演算を実行して確認

a = [5, 3, 8, 1]
print(len(a), 8 in a, 7 not in a)
print(a + [0], [0] * 3)
print(a[1:3], a[::-1], a[-1])
del a[0]; print(a)
print(sorted(a), list(reversed(a)), a)
for i, v in enumerate(["A", "B"], start=1): print(i, v)
print(list(zip(["pen", "note"], [120, 300])))
print(min(a), max(a), sum(a))
print(any(x > 5 for x in a), all(x > 0 for x in a))
4 True True
[5, 3, 8, 1, 0] [0, 0, 0]
[3, 8] [1, 8, 3, 5] 1
[3, 8, 1]
[1, 3, 8] [1, 8, 3] [3, 8, 1]
1 A
2 B
[('pen', 120), ('note', 300)]
1 8 12
True True

スライスで取り出す・置き換える・消す

スライス a[開始:終了:間隔] は「開始は含み、終了は含まない」範囲です。 代入や del と組み合わせると、範囲ごと置き換え・削除ができます。

a = [1, 2, 3, 4, 5]
a[1:3] = ["x"]; print(a)           # 2要素を1要素に置き換え
a = [1, 2, 3, 4, 5]
a[::2] = [0, 0, 0]; print(a)       # 1つおきに置き換え(個数を合わせる)
del a[::2]; print(a)               # 1つおきに削除
x, *rest = [10, 20, 30]; print(x, rest)   # アンパック
[1, 'x', 4, 5]
[0, 2, 0, 4, 0]
[2, 4]
10 [20, 30]

間隔つきスライス(a[::2])への代入は個数が一致しないとエラーになります。 実際に2要素の範囲へ3要素を入れると ValueError: attempt to assign sequence of size 3 to extended slice of size 2 になりました。

zip は短い方に合わせる

print(list(zip([1, 2, 3], ["a", "b"])))
list(zip([1, 2, 3], ["a", "b"], strict=True))
[(1, 'a'), (2, 'b')]
ValueError: zip() argument 2 is shorter than argument 1

長さの違いを見落としたくないときは strict=True(3.10以降)を付けます。 空のリストに max() を使うとエラーになるので、max([], default=0) のように既定値を渡すと安全です。

x = x.sort() で None になる罠

sort() は元のリストを並べ替えて None を返すため、結果を代入すると変数が None になります。

x = [3, 1, 2]
x = x.sort()
print(x)
x.append(1)
None
AttributeError: 'NoneType' object has no attribute 'append'

直し方は2通りです。

x = [3, 1, 2]
x.sort()          # 1. 代入しない(元を変える)
y = sorted(x)     # 2. sorted で新しいリストを受け取る(元は残る)

同じ罠は append・extend・insert・reverse・remove・clear にもあります。 「元を変えるメソッドは None を返す」と覚えておくと迷いません。

sort と sorted の違い・key と reverse の使い方

a.sort() sorted(a)
元のリスト 変わる 変わらない
戻り値 None 新しいリスト
使える対象 リストだけ タプル・集合・辞書など何でも
引数 key・reverse key・reverse

key には「並べ替えの基準を返す関数」を渡します。 複数条件はタプルで返し、数値の降順は - を付けると1回で書けます。

members = [
    {"name": "佐藤", "age": 31, "score": 82},
    {"name": "鈴木", "age": 25, "score": 95},
    {"name": "高橋", "age": 31, "score": 77},
]
print([m["name"] for m in sorted(members, key=lambda m: m["score"], reverse=True)])
print([m["name"] for m in sorted(members, key=lambda m: (-m["age"], m["score"]))])
from operator import itemgetter
print([m["name"] for m in sorted(members, key=itemgetter("age", "score"))])

words = ["banana", "apple", "Cherry"]
print(sorted(words), sorted(words, key=str.lower))
print(sorted(["10", "9", "100"]), sorted(["10", "9", "100"], key=int))
['鈴木', '佐藤', '高橋']
['高橋', '佐藤', '鈴木']
['鈴木', '高橋', '佐藤']
['Cherry', 'apple', 'banana'] ['apple', 'banana', 'Cherry']
['10', '100', '9'] ['9', '10', '100']
  • 大文字は小文字より前に並びます(文字コード順)。大文字小文字を区別しないなら key=str.lower。
  • 数字の文字列は辞書順になるので、数値として並べるなら key=int。
  • Pythonの並べ替えは安定ソート(同じ値の元の順序を保つ)です。

コピー:代入・浅いコピー・深いコピーの違い

b = a はコピーではなく、同じリストに別の名前を付けるだけです。 copy() や a[:] は外側だけを新しくする「浅いコピー」で、中のリストは共有されます。

import copy
a = [[1, 2], [3, 4]]
b = a                 # 代入
c = a.copy()          # 浅いコピー
d = copy.deepcopy(a)  # 深いコピー
a[0].append(99)
a.append([5])
print("a", a); print("b", b); print("c", c); print("d", d)
print(b is a, c is a, c[0] is a[0], d[0] is a[0])
a [[1, 2, 99], [3, 4], [5]]
b [[1, 2, 99], [3, 4], [5]]
c [[1, 2, 99], [3, 4]]
d [[1, 2], [3, 4]]
True False True False
方法 外側の追加・削除 中身(入れ子)の変更 用途
b = a 共有 共有 同じものを指したいとき
a.copy() / a[:] / list(a) 独立 共有 中身が数値・文字列だけのとき
copy.deepcopy(a) 独立 独立 入れ子のリスト・辞書

[[0]*3]*3 で全行が変わる罠

掛け算(*)による繰り返しは、同じ内側のリストを3回並べるだけです。

grid = [[0] * 3] * 3
grid[0][0] = 1
print(grid)

grid = [[0] * 3 for _ in range(3)]
grid[0][0] = 1
print(grid)
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]

2次元リストは内包表記で1行ずつ新しく作ると、行ごとに独立します。 [0] * 3 のように中身が数値なら * で問題ありません。

内包表記で変換・絞り込み

内包表記 [式 for 変数 in リスト if 条件] は、for文と append を1行にまとめた書き方です。

prices = [120, 980, 450, 3000]
print([round(p * 1.1) for p in prices if p >= 500])   # 絞り込み+変換
print(["高" if p >= 1000 else "低" for p in prices])   # 条件で値を変える
print([(r, c) for r in range(2) for c in range(2)])   # 二重ループ
[1078, 3300]
['低', '低', '低', '高']
[(0, 0), (0, 1), (1, 0), (1, 1)]

if の位置で意味が変わります。 後ろの if は「絞り込み」、前の A if 条件 else B は「値の切り替え」です。10万件で比べると、for文+append が10回で44.7ミリ秒、内包表記が34.2ミリ秒でした(Python 3.14.7、timeit の最小値)。

実務でよく使うリスト操作

重複を除く(順序を保つ)

tags = ["python", "sql", "python", "git", "sql"]
print(list(dict.fromkeys(tags)))   # 最初に出た順を保つ
print(sorted(set(tags)))           # 順序は捨てて並べ替え

rows = [{"id": 1, "v": "a"}, {"id": 2, "v": "b"}, {"id": 1, "v": "c"}]
seen, uniq = set(), []
for r in rows:
    if r["id"] not in seen:
        seen.add(r["id"]); uniq.append(r)
print(uniq)
['python', 'sql', 'git']
['git', 'python', 'sql']
[{'id': 1, 'v': 'a'}, {'id': 2, 'v': 'b'}]

set は順序を保証しないため、順序を残したいときは dict.fromkeys を使います(辞書は挿入順を保つ仕様)。辞書のように set に入れられない要素は、キーだけを set で管理します。

入れ子を平坦にする

import itertools
nested = [[1, 2], [3], [], [4, 5]]
print([x for row in nested for x in row])
print(list(itertools.chain.from_iterable(nested)))

def flatten(xs):          # 深さが不定のとき
    for x in xs:
        if isinstance(x, list):
            yield from flatten(x)
        else:
            yield x
print(list(flatten([1, [2, [3, [4]], 5]])))
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

N件ずつに分割する(itertools.batched)

Python 3.12で追加された itertools.batched を使うと、N件ずつのかたまりに分けられます。 3.13からは strict=True で端数をエラーにできます。

from itertools import batched
ids = list(range(1, 11))
print(list(batched(ids, 4)))
print([list(b) for b in batched(ids, 4)])
list(batched(ids, 4, strict=True))
[(1, 2, 3, 4), (5, 6, 7, 8), (9, 10)]
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
ValueError: batched(): incomplete batch

3.11以前ではスライスで同じ結果になります:[ids[i:i + 4] for i in range(0, len(ids), 4)]。

その他の便利な操作

from collections import Counter
import bisect, itertools
print(Counter(["pen", "note", "pen"]).most_common(1))   # 最頻値
s = [10, 20, 30]; bisect.insort(s, 25); print(s)       # 並びを保って挿入
print(list(itertools.pairwise([1, 4, 9])))             # 隣り合う組
print([1, 2] < [1, 3], [2] > [1, 9])                   # 先頭から順に比較
[('pen', 2)]
[10, 20, 25, 30]
[(1, 4), (4, 9)]
True True

計算量の目安と速度の実測

リストは「末尾の追加・削除と番号でのアクセスが速く、先頭への挿入・削除と in 検索は件数に比例して遅くなる」データ構造です。 公式Wiki「TimeComplexity」(CPython)の表から、よく使う操作を抜き出しました。

操作 計算量 メモ
a[i] / a[i] = x / len(a) O(1) 件数に関係なく一定
append(x) / pop() O(1) 末尾の操作
pop(0) / insert(0, x) / del a[i] O(n) 後ろの要素をずらす
x in a / index / count / remove O(n) 先頭から順に探す
extend(b) / a[i:j] O(k) k は追加・取り出す件数
sort() / sorted() O(n log n)
min / max / sum O(n)

10万件で実測すると(Python 3.14.7、timeit で3回の最小値)、差がはっきり出ました。

処理(10万回) 時間
list.append(x) 3.2 ms
list.insert(0, x) 1,134.7 ms
deque.appendleft(x) 4.1 ms
list.pop(0) 1,000.8 ms
deque.popleft() 4.0 ms
99_999 in list(10万件、1,000回) 756.43 ms
99_999 in set(10万件、1,000回) 0.036 ms

先頭の出し入れが多いなら collections.deque、in の検索が多いなら set に変えると、処理時間が大きく変わります。

リスト・タプル・array・dequeの使い分け

型 変更 得意なこと 100万件の sys.getsizeof
list できる 汎用。末尾の追加、番号アクセス 8,000,056 バイト
tuple できない 固定の組、辞書のキー、関数の戻り値 8,000,048 バイト
array.array("i") できる 同じ型の数値を省メモリで持つ 4,000,080 バイト
collections.deque できる 両端の追加・削除(キュー) —

※ sys.getsizeof は入れ物自体の大きさで、中の整数オブジェクトは含みません(array は値を直接持つため小さくなります)。

迷ったら list、変更しない組は tuple、両端の出し入れは deque、大量の数値計算はNumPy を選ぶのが目安です。

よくある質問

Q. リストの末尾の要素を取り出すには? A. 取り出すだけなら a[-1]、取り出して削除するなら a.pop() です。空のリストだと IndexError になるので、if a: で確認してから使います。

Q. ループ中に要素を削除するとおかしくなります。 A. ループ中のリストを変更すると、要素がずれて飛ばされることがあります。 a = [x for x in a if 条件] で新しいリストを作るのが確実です。

Q. 2つのリストの共通部分や差分を取るには? A. 順序が不要なら set(a) & set(b)(共通)、set(a) - set(b)(差分) です。順序を保つなら [x for x in a if x in set_b] のように、比較先だけ set にします。

Q. += と extend は同じですか? A. リストに対する a += b は a.extend(b) と同じく元のリストを変更します。 a = a + b は新しいリストを作るため、別名(b = a など)で参照している側には反映されません。

まとめ

  • リストのメソッドは11個。元を変えるメソッドは None を返すので x = x.sort() と書かない
  • 並べ替えは元を残すなら sorted、変えるなら sort。基準は key、降順は reverse=True
  • copy() は浅いコピー。入れ子なら copy.deepcopy、2次元は内包表記で行ごとに作る
  • 重複除去は list(dict.fromkeys(a))、分割は itertools.batched(3.12以降)
  • 先頭の出し入れは deque、大量の in 検索は set に変えると速い
  • 範囲外でもスライスはエラーにならず、添字アクセスは IndexError

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Python リスト 操作 一覧|全メソッド逆引きと3.14実行結果」

株式会社RJCでは、基本の書き方も実際に動かして確かめ、その結果をプロジェクトの中で仲間と共有しています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?