「Pythonは遅い」と感じることはないだろうか。実は、標準機能の使い方を少し工夫するだけで、処理速度を大きく改善できる方法があるという。
Pythonは、初心者でも“取りあえず動くコード”を手早く書ける手軽さが魅力のプログラミング言語だ。情シスの現場でも、ログ解析やファイル管理、Officeアプリの操作など、さまざまな処理を自動化して業務効率化を進めている担当者もいる。
一方でPythonは、機械学習やディープラーニング、自然言語処理といったAI開発全般でも幅広く利用されている。AI領域には専用ライブラリが豊富にそろっており、効率的に開発できる半面、コードの複雑化やデータ量の増加に伴って、動作が急に遅く感じられることもある。
そんなPythonに対し、少しの工夫でパフォーマンスを向上させ、その実力を引き出す“裏ワザ”が公開された。ほんの少しの改善で大きな効果が得られる、裏ワザとは。
Pythonは扱いやすい一方で、「処理が遅い」「大量データに弱い」といった声が聞かれることもある。だが、言語仕様や標準ライブラリを上手に活用すれば、多くの場面で軽快に動作させることが可能だ。ディープラーニングエンジニアでありPythonプログラマーでもあるディド・グリゴロフ氏もそう語る。
グリゴロフ氏は2025年11月5日、「10 Smart Performance Hacks For Faster Python Code」という記事を「PyCharmブログ」に投稿した。記事の冒頭で同氏は「PythonはWeb開発から人工知能、データエンジニアリングまで幅広い用途で利用されている。だが、その洗練された構文の裏には、効率的なスクリプトを遅くしてしまう潜在的なパフォーマンスボトルネックが存在する」と述べる。そのボトルネックを排除し、Pythonの性能を引き出す「10のハック」を紹介している。
以下に、その概要を簡単にまとめた。サンプルコードについては割愛しているので、詳細はは元記事を参照してほしい。
コレクション内の要素の存在確認をリストで(x in some_list)と書くと、リストの長さに比例して検索コストが増大し、線形計算量(O(n))が発生する。これに対して、集合(set)を使えば平均して定数時間(O(1))で済む。特に、大規模データでの値の存在確認や重複除去、集合演算(和・積・差)する場合は、リストよりもsetを使う方が効率的だろう。
リストや辞書、配列などの大きなオブジェクトをコピーして使用すると、時間とメモリの両面でオーバーヘッドが発生する。そのため、可能な限りコピーせずに済む「インプレースメソッド」を使うことが望ましい。特に、大規模または複雑なデータ構造を扱う場合、これにより効率的でメモリ消費の少ないコードを実現できる。
通常、Pythonクラスでは各インスタンス属性が動的辞書(__dict__)に格納されるため柔軟性は高いが、その分メモリオーバーヘッドや属性アクセスのコストがやや大きい。「__slots__」を用いて属性名を固定して宣言すれば「__dict__」を使わずに済み、メモリ使用量を削減できるとともに、属性アクセスもわずかに高速化される。特に、多数のインスタンスを生成する軽量データコンテナに有効な手法だ。
平方根を求める場合、指数演算子(**)で0.5乗するよりも、「math.sqrt(n)」を使用した方が高速かつ処理精度も優れている。「math.sin()」や「math.log()」なども同様であり、ループや大規模な計算を多用する処理では特に高速化が期待できる。
リストや配列を動的に構築すると、内部で何度もメモリの拡張やコピーが発生し、オーバーヘッドとなる。データ構造の最終サイズが事前に予測できる場合は、メモリをあらかじめ割り当てることでパフォーマンスを大幅に向上させることができる。この手法は、数値計算やシミュレーション、大規模データ処理において特に有効だ。
Pythonの例外処理は便利ではあるが、例外発生時にはスタックの解放やコンテキストの切り替えが起きるため、コストが比較的高い。ホットループ(繰り返し実行される処理や大量データの処理)で例外処理を多用すると、パフォーマンスが大幅に低下する可能性がある。そのため、例外が頻繁に発生するホットループでは条件チェック(if、in、isなど)を使ってエラーを事前に防ぐ方が、高速かつ安定した処理を実現できる。
関数内で特定のロジックを繰り返し使用する場合、グローバル関数よりもローカル関数(関数内で定義された関数)の方が、名前解決の面で高速化の恩恵を受ける。さらに、ロジックを局所化してモジュール化できるため、コード構造も整理しやすくなる。この手法は、ループ処理やデータ変換、再帰プロセスなど、同じ操作を複数回適用する関数で特に有効だ。
順列や組み合わせ、直積などの反復子ベースの処理には、itertoolsモジュールを利用することで高速化が可能だ。「product()」「permutations()」「combinations()」などの関数はCで実装されており、結果を遅延生成するためメモリ効率が高く、パフォーマンスも向上する。特に、複雑なデータ操作やアルゴリズム開発、シミュレーション、検索処理、競技プログラミングなどの問題解決タスクに適している。
ソート済みのリストに対して線形探索や手動で挿入すると、O(n)の時間がかかり、リストが大きくなるほど効率が低下する。これに対して、bisectモジュール(bisect_left()、bisect_right()、insort()など)を使用すれば、二分探索によりO(log n)で処理でき、パフォーマンスが向上する。リーダーボードやイベントタイムラインの管理などに特に有効だ。
ループ内で同じ関数を複数回呼び出すと、その関数が高負荷であったり同じ結果を返したりする場合、不要なオーバーヘッドや重複計算が積み重なってしまう。可能な限りループの外で結果を計算しローカル変数に格納しておき、ループ内ではその変数を参照する方が効率的だ。シンプルな手法だが、実行速度だけでなくコードの明瞭性も向上する。
ここで紹介した10のハックに共通するのは、Pythonの言語仕様やライブラリを効率的に活用し、無駄や重複、過剰な柔軟性を削ぎ落とす点だ。これらは速度やメモリ使用量、スケーラビリティを意識した小さな改善が中心であり、コード全体の書き換えを必ずしも必要としない。
グリゴロフ氏も、いずれのハックにおいて実際に動作時間の短縮を確認しており、「最も効果的な最適化とは、速度と明瞭性のバランスを取ることだ」と述べている。Pythonを扱うエンジニアにとって、限られた時間とリソースで効率を高める「小さな最適化」として、取り入れてみてはいかがだろうか。
上司X: Pythonのコードを高速化する10のスマートなパフォーマンスハックがある、という話だよ。
ブラックピット: Pythonのコードにちょっとした工夫をすると処理が速くなると。
上司X: そういうことだね。まさに「ハック」というヤツだ。
ブラックピット: 造詣が深い人だからこそ、こういうハックネタが出せるのでしょうね。
上司X: グリゴロフ氏はPython歴17年だとか。
ブラックピット: さすがですね。
上司X: 詳しくは投稿を見てほしいが、これらのテクニックについて、実際にどの程度処理時間が短縮されるのか、その具体的な効果を記事で示しているのも面白いな。
ブラックピット: しかも、コード全般を書き換えるのではなく、一部を書き換えるだけで済む手法ばかりなんですよね。
上司X: 既にコードを書き終わって「なんか遅いかも」と思っている人でも、大幅な変更をすることなくパフォーマンスが改善できるかもしれないからな。ちょっとした工夫で劇的な効果が期待できる。そんなハックがあれば、Pythonに限らずどんどん紹介していきたいものだな。
年齢:36歳(独身)
所属:某企業SE(入社6年目)
昔レーサーに憧れ、夢見ていたが断念した経歴を持つ(中学生の時にゲームセンターのレーシングゲームで全国1位を取り、なんとなく自分ならイケる気がしてしまった)。愛車は黒のスカイライン。憧れはGTR。車とF1観戦が趣味。笑いはもっぱらシュールなネタが好き。
年齢:46歳
所属:某企業システム部長(かなりのITベテラン)
中学生のときに秋葉原のBit-INN(ビットイン)で見たTK-80に魅せられITの世界に入る。以来ITひと筋。もともと車が趣味だったが、ブラックピットの影響で、つい最近F1にはまる。愛車はGTR(でも中古らしい)。人懐っこく、面倒見が良い性格。
Copyright © ITmedia, Inc. All Rights Reserved.
製品カタログや技術資料、導入事例など、IT導入の課題解決に役立つ資料を簡単に入手できます。