Python

Pythonのpop()の使い方:リスト・辞書・dequeの違いとpop(0)が遅い理由

Pythonのpop()の使い方:リスト・辞書・dequeの違いとpop(0)が遅い理由

Pythonのpop()は、要素を削除すると同時にその値を返すメソッドです。リストでは位置を、辞書ではキーを指定し、setやdequeにも同じ名前のメソッドがあります。名前は同じでも引数の意味、空のときの例外、処理の速さは型ごとに違います。この記事では2026年9月時点のPython公式ドキュメントとPython 3.14.6での実行結果をもとに、型別の書き方、IndexErrorやKeyErrorの原因、ループ中のpopで起きる不具合、pop(0)の速度を100万件まで計測した結果とdequeへ切り替える基準を整理しました。

まとめ:Pythonのpop()を型別に使い分けるための書き方と判断の結論

リストのpop()は引数なしなら末尾、pop(i)ならi番目を取り出して返します。取り出した値を使わないならdel、値で消したいならremove()を選びます。

辞書のpop(key)はキーが無いとKeyErrorになります。存在が不確かなキーには、第2引数にNoneなどのデフォルト値を必ず渡してください。

先頭から順に取り出す処理は、リストのpop(0)ではなくcollections.dequeのpopleft()で書きます。手元の計測では要素数10万で約470倍、100万で約2,900倍の差が出ました。要素数が数百程度に収まると分かっている場合を除き、キュー処理にリストは使いません。

リストのpop()の基本構文と戻り値・インデックス指定と負の番号の挙動

リストのpop()はPython公式ドキュメントの組み込み型でsequence.pop(index=-1, /)と定義されています。引数の既定値が-1なので、何も渡さなければ末尾の要素が対象です。

引数なしのpop()で末尾を取り出す書き方と元のリストが書き換わる点

stack = [10, 20, 30, 40]
last = stack.pop()
print(last)    # 40
print(stack)   # [10, 20, 30]

pop()は新しいリストを作らず、元のリストそのものを書き換えます。関数の引数として受け取ったリストにpop()を使うと、呼び出し元のリストも短くなります。元を残したい場合は、先にitems = original.copy()で複製してから取り出してください。

公式チュートリアルのデータ構造の章は、append()で積んでpop()で取り出す組み合わせを「リストをスタックとして使う」方法として紹介しています。後から入れたものが先に出るLIFOの動きです。

pop(0)やpop(-2)で位置を指定したときに取り出される要素と例

引数には0始まりの位置を渡します。負の数は末尾から数えた位置で、-1が最後、-2が最後から2番目です。

a = [10, 20, 30, 40, 50]
print(a.pop(0))    # 10  先頭
print(a.pop(-2))   # 40  最後から2番目
print(a.pop(1))    # 30  残りの2番目
print(a)           # [20, 50]

3行目のpop(1)が30を返すのは、直前の2回で要素が抜けて位置がずれているからです。同じリストに続けてpop(i)を使うときは、取り出すたびに後ろの要素の番号が1つずつ前に詰まる点を前提に書きます。

pop()・remove()・delの違いを戻り値と指定方法で比べた早見表

リストから要素を消す方法は3つあり、指定の仕方と戻り値が違います。

書き方 指定するもの 戻り値 見つからないとき
a.pop(i) 位置(省略で末尾) 取り出した値 IndexError
a.remove(x) 値(最初の1つだけ) None ValueError
del a[i] 位置・スライス なし(文) IndexError

選び方は戻り値を使うかどうかで決まります。取り出した値をその後の処理で使うならpop()、使わないならdelです。del a[1:3]のようにスライスで範囲をまとめて消せるのはdelだけです。

辞書のpop()とpopitem()でキーを取り出す書き方とデフォルト値の指定

辞書のpop()は位置ではなくキーを受け取り、対応する値を返して項目を削除します。リストと違って引数は省略できず、d.pop()と書くとTypeError: pop expected at least 1 argument, got 0になります。

dict.pop(key, default)でKeyErrorを避ける書き方と使う場面

params = {"page": "2", "sort": "date", "debug": "1"}
debug = params.pop("debug", None)   # "1" を取り出して削除
token = params.pop("token", None)   # キーが無いので None
print(params)                        # {'page': '2', 'sort': 'date'}

第2引数を渡すと、キーが無いときに例外ではなくその値が返ります。Python 3.14.6のdict.popのdocstringも「キーが見つからなければdefaultを返し、無ければKeyErrorを送出する」という内容です。上の例のように、受け取った設定値から内部用のキーを抜き取り、残りを別の関数へ渡す処理でよく使います。

取り出さずに値を読むだけならd.get(key)で十分です。辞書とnamedtuple・dataclassのどれでデータを持つかはPython namedtupleとは?名前付きタプルの使い方とdataclass・dictとの違いで比べています。

popitem()が後から入れた順に返すLIFOの仕様とOrderedDictの違い

popitem()はキーを指定せず、(キー, 値)のタプルを1組取り出します。取り出される順序はLIFOで、最後に追加した項目が先に出ます。Python 3.7より前は順序が保証されていなかったため、古いコードでは任意の1組を取る用途で使われていました。

from collections import OrderedDict

d = {"a": 1, "b": 2, "c": 3}
print(d.popitem())                 # ('c', 3)

o = OrderedDict(a=1, b=2, c=3)
print(o.popitem(last=False))       # ('a', 1)  先頭から取り出す

先頭から取り出したい場合はOrderedDictを使います。collectionsモジュールのドキュメントのとおり、popitem(last=False)でFIFO、既定のlast=TrueでLIFOです。古い項目から捨てていくキャッシュを自作するときは、このlast=Falseが役に立ちます。

setとdeque、heapqのpop系メソッドで取り出される要素の違いと注意

リストと辞書以外にも、取り出しのメソッドを持つ型があります。名前が似ていても、どの要素が出てくるかの規則はそれぞれ違います。

set.pop()が任意の要素を返す仕様と順序を前提にしてはいけない理由

set.pop()のdocstringは「任意のset要素を削除して返す」です。どの要素が出るかは決まっていません。

print({3, 1, 2}.pop())         # 手元では 1
print({"x", "y", "z"}.pop())   # 実行するたびに変わりうる

手元では整数のsetから1が出ましたが、これは実装の都合による結果です。文字列のハッシュ値は起動ごとに変わるため、文字列のsetでは実行のたびに別の要素が出る可能性があります。「最初に入れたもの」や「最小値」を取り出す目的でsetのpop()を使うと、テストでは通って本番で壊れる不具合の原因です。順序が必要ならリストかdeque、最小値ならheapqを選びます。

dequeのpopleft()とheappop()で先頭や最小値を取り出す実装

from collections import deque
import heapq

q = deque(["job1", "job2", "job3"])
q.append("job4")
print(q.popleft())            # job1  入れた順に取り出す

tasks = [(3, "低"), (1, "高"), (2, "中")]
heapq.heapify(tasks)
print(heapq.heappop(tasks))   # (1, '高')  最小の要素

h = [3, 9, 1, 7]
heapq.heapify_max(h)
print(heapq.heappop_max(h))   # 9  Python 3.14以降

dequeは両端から出し入れできる型で、pop()で右端、popleft()で左端を取り出します。heapqのドキュメントによると、heappop()は最小の要素を返し、ヒープが空ならIndexErrorを送出します。Python 3.14からはheappop_max()など最大ヒープ用の関数も加わり、以前のように値の符号を反転させる工夫が要らなくなりました。3.14のほかの変更点はPython 3.14のJITコンパイラとは?有効化の手順と実測、フリースレッド版と新機能で解説しています。

スタックとキューをどう使い分けるかという設計の話はスタックとキューの違い|FIFO・LIFOと使い分け・Python実装にまとめています。

pop()で出るIndexErrorとKeyErrorの原因とメッセージ別の対処

以下のエラーメッセージは、すべてPython 3.14.6で実際に実行して表示されたものです。メッセージの文言から、どの型のどの操作で失敗したかを見分けられます。

空のリストや範囲外の位置で出るIndexErrorの見分け方と回避の書き方

  • [].pop():IndexError: pop from empty list
  • [1].pop(5):IndexError: pop index out of range
  • deque().popleft():IndexError: pop from an empty deque
  • [1].pop("0"):TypeError: 'str' object cannot be interpreted as an integer

空のリストかどうかはif items:で確かめてから取り出します。空のリストは偽として扱われるので、len()で比べる必要はありません。4行目は、入力フォームやCSVから読んだ文字列の番号をそのまま渡したときに起きます。int()で変換してから渡してください。

辞書とsetのKeyError、タプルや文字列にpopが無いAttributeError

辞書とsetは、失敗したときにIndexErrorではなくKeyErrorを送出します。キー"k"が無い辞書でpop("k")を呼ぶとKeyError: 'k'、空の辞書のpopitem()はKeyError: 'popitem(): dictionary is empty'、空のsetのpop()はKeyError: 'pop from an empty set'です。辞書とsetをまとめてtryで囲むときは、捕まえる例外をKeyErrorにします。

タプルと文字列にはpop()自体がありません。(1, 2).pop()はAttributeError: 'tuple' object has no attribute 'pop'になります。どちらも作成後に変更できない型だからです。文字列の末尾を1文字落としたいならs[:-1]、タプルならlist(t)でリストに変えてから操作します。

forループの中でpop()すると要素が飛ばされる不具合と安全な書き方

ループで回しているリストから、同じループの中でpop()すると、要素が取りこぼされます。

x = [1, 2, 2, 3, 2, 4]
for i, v in enumerate(x):
    if v == 2:
        x.pop(i)
print(x)   # [1, 2, 3, 4]  2が1つ残る

# 安全な書き方:条件に合わないものだけで作り直す
x = [1, 2, 2, 3, 2, 4]
x = [v for v in x if v != 2]
print(x)   # [1, 3, 4]

2番目の要素を取り出した時点で、3番目にあった2が2番目に詰まります。ループは次の3番目へ進むため、詰まってきた2は一度も調べられません。条件で消すならリスト内包表記で作り直すのが安全です。元のリストを書き換える必要があるときはx[:] = [v for v in x if v != 2]と書きます。全部を順に取り出して処理するなら、while x:の中でx.pop()を呼ぶ形なら位置のずれは起きません。

list.pop(0)が遅い理由をtimeitで実測した結果とdequeへ切り替える基準

ここからはリストとdequeの内部の違いが結果に表れる話です。Python Wikiの計算量一覧は、リストの末尾の取り出しをO(1)、途中の取り出しをO(n)としています。

要素数1万・10万・100万でpop()とpop(0)とpopleft()を計測した値

標準ライブラリのtimeitモジュールで、取り出しと追加を1組にした操作の1回あたりの時間を測りました。環境はPython 3.14.6(Windows 11・ARM64)で、3回繰り返した最小値です。要素数を一定に保つため、取り出すたびに1つ追加しています。

import timeit

n = 100_000
setup = f"from collections import deque; l = list(range({n})); q = deque(range({n}))"
print(timeit.timeit("l.pop(); l.append(0)", setup, number=100_000))
print(timeit.timeit("l.pop(0); l.append(0)", setup, number=2_000))
print(timeit.timeit("q.popleft(); q.append(0)", setup, number=100_000))
要素数 pop() pop(0) popleft()
1万 53ns 2,398ns 43ns
10万 33ns 18,998ns 40ns
100万 32ns 205,807ns 71ns

pop()とpopleft()は要素数が100倍になってもほぼ横ばいです。pop(0)だけが要素数にほぼ比例して伸び、100万件では1回に約0.2ミリ秒かかりました。CPythonのリスト実装はリストを連続した配列として持っているため、先頭を抜くと残り全部を1つずつ前へ詰め直すからです。100万件のリストを先頭から全部取り出すと、平均の長さが約半分なので単純計算で100秒前後かかります。同じ処理がdequeなら0.1秒に収まる計算です。計算量の考え方そのものはPythonでフィボナッチ数列を再帰関数で実装する方法|計算量とメモ化でも扱っています。

pop(0)をそのまま使ってよい条件とdequeへ置き換えるべき場面

判断は要素数の上限が決まっているかどうかで分けます。1万件でもpop(0)は1回約2.4マイクロ秒なので、画面の入力項目や設定値のように数十〜数百件と上限が決まっているリストなら、書き換える意味はありません。インデックスで途中の要素を読む処理が多い場合も、リストのままが向いています。dequeは両端の出し入れが速い代わりに、中央付近を位置で読むのは遅いからです。

逆に、ファイルの行、APIの応答、ジョブの一覧のように件数が入力次第で増えるものを先頭から処理するなら、最初からdequeで書きます。「今は数百件だから」でリストを選ぶのは失敗の典型です。データ量が10倍になった日に処理時間は約10倍ではなく約100倍に伸び、原因が分かりにくい遅延として表に出ます。直近N件だけ残したい場合はdeque(maxlen=N)にすると、あふれた古い要素が自動で捨てられます。

業務システムのキュー処理をpopだけで済ませずに設計し直す場面

dequeのpopleft()が扱うのは、1つのプロセスのメモリ上にあるデータだけです。collectionsのドキュメントはdequeの両端の操作をスレッドセーフとしていますが、プロセスが落ちれば中身は消えます。受注データの取り込みや帳票の一括生成のように、取り出した後の処理が失敗したら再実行する、処理済みを記録して二重に動かさない、といった要件が出てきたら、pop()の選び方ではなくジョブキューやデータベースを含めた設計の問題です。

この段階で、既存の仕組みに組み込むのか作り直すのかを判断する担い手が社内にいない場合は、フルスクラッチ開発のように要件から処理の流れを設計し直す外部の支援を使う方法もあります。

よくある質問

Pythonのpop()について検索されることの多い疑問に答えます。

pop()とa[-1]で末尾を取得する方法の違いは何ですか?

a[-1]は末尾の値を読むだけで、リストは変わりません。a.pop()は同じ値を返したうえで、リストから削除する点が違いです。空のリストではどちらもIndexErrorですが、メッセージはa[-1]がlist index out of range、pop()がpop from empty listと異なります。値を確かめてから消すかどうか決める処理では、先にa[-1]で読み、必要なときだけpop()します。

pop()で複数の要素をまとめて取り出すことはできますか?

pop()が一度に取り出せるのは1つだけです。複数をまとめて取り出したい場合は、スライスで値を受け取ってからdelで消します。末尾の3件ならlast3 = a[-3:]の後にdel a[-3:]です。ループでpop()を3回呼んでも同じ結果になりますが、取り出した順が逆になる点に注意してください。

辞書のpop()とdel d[key]はどちらを使えばよいですか?

削除した値を使うならpop()、使わないならdelです。キーが無い可能性がある場合は、delだとKeyErrorを避けるためにif key in d:の確認が要ります。d.pop(key, None)なら1行で「あれば消す、無ければ何もしない」を書けるため、戻り値を使わない場合でもこの書き方が選ばれることがあります。

文字列の最後の1文字をpop()のように取り除くにはどうしますか?

文字列は変更できない型なのでpop()はありません。s[-1]で最後の1文字を読み、s = s[:-1]で残りを作り直すのが基本の形です。末尾の改行や特定の文字を落としたいだけなら、s.rstrip("\n")やs.removesuffix(".csv")の方が意図がはっきりします。1文字ずつ何度も取り出すなら、list(s)でリストにしてからpop()を使います。

複数のスレッドから安全に要素を取り出すにはどうしますか?

取り出して処理する係と、追加する係が別のスレッドに分かれる構成なら、標準ライブラリのqueue.Queueを使います。get()は要素が入るまで待てるため、空かどうかを自分で確かめる必要がありません。dequeのpopleft()も両端の操作はスレッドセーフですが、空のときは待たずにIndexErrorになります。複数のプロセスやサーバーをまたぐなら、メモリ上の型ではなくジョブキューの仕組みを使います。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.09.28 テックブログ タイムズカーの不正アクセスと約660万件の流出|免許証画像を退会者まで残さない保管設計
  2. 2026.09.25 コラム 最低賃金引き上げ【令和8年度】47都道府県の改定額・発効日と企業の対応手順
  3. 2025.11.28 コラム ポリコレとは?意味と具体例、「行き過ぎ」「逆差別」と言われる理由を法律と調査で整理
  4. 2026.09.05 コラム 犯罪収益移転防止法の本人確認:2027年4月の対面IC読み取り義務化と改修要件
  5. 2026.07.21 テックブログ Apache Tomcatの脆弱性一覧【2026年9月】15件の修正版9.0.122・10.1.60・11.0.26と影響確認・対応手順

RELATED POSTS 関連記事

目次