---
title: "Pythonのpop()の使い方：リスト・辞書・dequeの違いとpop(0)が遅い理由"
url: "https://www.issoh.co.jp/tech/details/17966/"
published: 2026-09-30
updated: 2026-09-30
categories: ["Python"]
publisher: "株式会社一創"
---

# 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公式ドキュメントの組み込み型](https://docs.python.org/ja/3/builtins/stdtypes.html)で`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()`で複製してから取り出してください。

[公式チュートリアルのデータ構造の章](https://docs.python.org/ja/3/tutorial/datastructures.html)は、`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との違い](https://www.issoh.co.jp/tech/details/3370/)で比べています。

### 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モジュールのドキュメント](https://docs.python.org/ja/3/library/collections.html)のとおり、`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のドキュメント](https://docs.python.org/ja/3/library/heapq.html)によると、`heappop()`は最小の要素を返し、ヒープが空なら`IndexError`を送出します。Python 3.14からは`heappop_max()`など最大ヒープ用の関数も加わり、以前のように値の符号を反転させる工夫が要らなくなりました。3.14のほかの変更点は[Python 3.14のJITコンパイラとは？有効化の手順と実測、フリースレッド版と新機能](https://www.issoh.co.jp/tech/details/9409/)で解説しています。

スタックとキューをどう使い分けるかという設計の話は[スタックとキューの違い｜FIFO・LIFOと使い分け・Python実装](https://www.issoh.co.jp/tech/details/4587/)にまとめています。

## 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の計算量一覧](https://wiki.python.org/moin/TimeComplexity)は、リストの末尾の取り出しをO(1)、途中の取り出しをO(n)としています。

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

標準ライブラリの[timeitモジュール](https://docs.python.org/ja/3/library/timeit.html)で、取り出しと追加を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のリスト実装](https://github.com/python/cpython/blob/main/Objects/listobject.c)はリストを連続した配列として持っているため、先頭を抜くと残り全部を1つずつ前へ詰め直すからです。100万件のリストを先頭から全部取り出すと、平均の長さが約半分なので単純計算で100秒前後かかります。同じ処理がdequeなら0.1秒に収まる計算です。計算量の考え方そのものは[Pythonでフィボナッチ数列を再帰関数で実装する方法｜計算量とメモ化](https://www.issoh.co.jp/tech/details/2755/)でも扱っています。

### 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()`の選び方ではなくジョブキューやデータベースを含めた設計の問題です。

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

## よくある質問

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`になります。複数のプロセスやサーバーをまたぐなら、メモリ上の型ではなくジョブキューの仕組みを使います。

## 関連記事

- [スタックとキューの違い｜FIFO・LIFOと使い分け・Python実装を図解](https://www.issoh.co.jp/tech/details/4587/)：pop()とpopleft()の使い分けの前提になるデータ構造の考え方です。
- [Python namedtupleとは？名前付きタプルの使い方とdataclass・dictとの違いを実測で解説](https://www.issoh.co.jp/tech/details/3370/)：辞書以外でデータを持つ型の選び方です。
- [再帰関数とは？自分を呼ぶ関数の仕組みとスタック・末尾再帰・実務判断を解説](https://www.issoh.co.jp/tech/details/15264/)：再帰をリストのスタックで書き換える考え方につながります。
- [Python 3.14のJITコンパイラとは？有効化の手順と実測、フリースレッド版と新機能](https://www.issoh.co.jp/tech/details/9409/)：heapqの最大ヒープ関数が加わった版の変更点です。
- [Python 3.13の新機能と3.12との違い｜GIL無効化の実測・削除モジュール・サポート期限](https://www.issoh.co.jp/tech/details/4042/)：スレッドとGILの前提が変わった経緯です。

---

出典: [Pythonのpop()の使い方：リスト・辞書・dequeの違いとpop(0)が遅い理由](<https://www.issoh.co.jp/tech/details/17966/>)（株式会社一創）
