Python 3.14では、標準ライブラリのheapqに最大ヒープ用の公開APIが追加されました。大きい値を順に取り出す処理を、負数化せずheapify_max()やheappop_max()で書けます。
対象: Python 3.14以上。確認日は2026年10月16日です。ITtrip側のWindows上のCPython 3.14.8で、本文の基本例と複合操作の結果を確認しています。
まずは最短例:最大値から順に取り出す
既存のlistをheapify_max()で最大ヒープに変換し、heappush_max()で値を追加します。その後、空になるまでheappop_max()を呼べば、大きい値から順に取り出せます。
import heapq
h = [4, 9, 1, 7]
heapq.heapify_max(h)
heapq.heappush_max(h, 12)
result = []
while h:
result.append(heapq.heappop_max(h))
print(result)想定出力です。
[12, 9, 7, 4, 1]heapify_max(h)は渡したhをその場で変換します。最大値はh[0]ですが、list全体が降順になる保証はありません。
Python 3.14で追加された5つの公開API
| 関数 | 役割 | 注意点 |
|---|---|---|
heapq.heapify_max(x) | 既存のlistを最大ヒープへその場で変換 | 戻り値ではなく、元のlistが変わる |
heapq.heappush_max(heap, item) | 最大ヒープへ値を追加 | 追加後もheap[0]が最大値 |
heapq.heappop_max(heap) | 最大値を削除して返す | 空のヒープではIndexError |
heapq.heappushpop_max(heap, item) | 値を追加してから最大値を返す | 追加した値自身が返る場合がある |
heapq.heapreplace_max(heap, item) | 現在の最大値を返し、新しい値で置き換える | 空のヒープではIndexError |
5つともPython 3.14で追加された公開APIです。通常のheapify()、heappush()、heappop()と_max関数を、同じヒープへ混在させないでください。
負数化する従来例とPython 3.14の対応
Python 3.13以下では公開された最大ヒープAPIがないため、数値を負数にして最小ヒープへ入れ、取り出すときに符号を戻す方法があります。
import heapq
values = [4, 9, 1, 7]
h = [-value for value in values]
heapq.heapify(h)
heapq.heappush(h, -12)
result = []
while h:
result.append(-heapq.heappop(h))
print(result)[12, 9, 7, 4, 1]Python 3.14以上では、同じ処理を冒頭のheapify_max()、heappush_max()、heappop_max()で直接書けます。対応関係は次のとおりです。
| 操作 | Python 3.14の最大ヒープ | 負数化する方法 |
|---|---|---|
| 既存データをヒープ化 | heapq.heapify_max(h) | h = [-x for x in values]の後にheapq.heapify(h) |
| 値を追加 | heapq.heappush_max(h, x) | heapq.heappush(h, -x) |
| 最大値を取り出す | heapq.heappop_max(h) | -heapq.heappop(h) |
| 最大値を見るだけ | h[0] | -h[0] |
負数化は数値向けの互換策で、文字列などにはそのまま使えません。Python 3.13以下でも、アンダースコア付きの内部関数を公開APIの代替として勧めることはできません。
heapreplace_maxとheappushpop_maxの違い
名前が似ていますが、処理の順序が違います。まずheapreplace_max()は、現在の最大値を先に取り出してから新しい値を追加します。次の[9, 4]は、2要素の最大ヒープとして有効です。
import heapq
h = [9, 4]
removed = heapq.heapreplace_max(h, 12)
print(removed)
print(h)9
[12, 4]現在の最大値9が返り、追加した12はヒープに残ります。
一方、heappushpop_max()は新しい値を追加してから、その時点の最大値を返します。
import heapq
h = [9, 4]
returned = heapq.heappushpop_max(h, 12)
print(returned)
print(h)12
[9, 4]12自身が最大なので、そのまま返り、元の[9, 4]が残ります。既存の最大値を先に除くのがheapreplace_max()、追加後の最大値を返すのがheappushpop_max()です。
実行版と機能の有無を確認する
まず、実際に使われているPythonの版を確認します。
python --version今回の確認環境では次の表示です。
Python 3.14.8プログラム内ではsys.version_infoとhasattr()を使うと、必要な関数が公開されているか確認できます。
import heapq
import sys
names = (
"heapify_max",
"heappush_max",
"heappop_max",
"heappushpop_max",
"heapreplace_max",
)
print(sys.version_info[:3])
print({name: hasattr(heapq, name) for name in names})(3, 14, 8)
{'heapify_max': True, 'heappush_max': True, 'heappop_max': True, 'heappushpop_max': True, 'heapreplace_max': True}ITtrip側で確認したCPython 3.13.7には、これらの公開_max関数はありませんでした。複数版へ対応するコードでは、少なくともhasattr(heapq, "heapify_max")を分岐条件にし、3.13以下では数値の負数化など、公開APIだけで構成した互換処理を用意します。
よくある間違い
heapify_max()後のlistを降順済みだと思う: 保証されるのは最大値がheap[0]にあることと、最大ヒープの規則を満たすことです。全要素の表示順には依存しません。- 最小ヒープ用と最大ヒープ用の関数を混ぜる: 同じ
hには、通常関数か_max関数のどちらか一方だけを使います。 - 空のヒープから取り出す:
heappop_max([])はIndexErrorになります。全件を処理するならwhile h:で空かどうかを確認できます。 - 内部APIへ依存する: アンダースコアで始まる名前は公開APIではありません。3.14未満への対応は、公開関数を使った負数化などで行います。
max・nlargest・sortedも検討する
データを更新しながら最大値を何度も取り出すのでなければ、別の標準機能の方が意図を直接表せる場合があります。
| 目的 | 候補 |
|---|---|
| 最大値を1個だけ求める | max(values) |
| 固定データから上位n個を得る | heapq.nlargest(n, values) |
| 全件を降順のlistにする | sorted(values, reverse=True) |
| 追加と最大値の取り出しを繰り返す | heapqの最大ヒープAPI |
用途とデータの扱い方で選びます。最大ヒープが常に最速である、という前提は置かず、必要な操作が「更新しながら最大値を繰り返し取り出すこと」かどうかで判断すると分かりやすくなります。
FAQ
Python 3.13でheappush_maxは使えますか?
公開APIとしては使えません。Python 3.14以上へ更新するか、数値なら負数化して通常のheappush()とheappop()を使います。
heapify_maxの戻り値を変数へ代入できますか?
heapify_max()はlistをその場で変換するため、変換後も元の変数を使います。h = heapq.heapify_max(h)とは書かず、heapq.heapify_max(h)と単独で呼び出します。
最大値を削除せず確認する方法は?
ヒープが空でなければh[0]で確認できます。削除も行う場合はheappop_max(h)を使います。


コメント