Pythonコードを高速化する11の最適化テクニック
Pythonはコンパイル言語ほど高速ではないことは周知の事実ですが、大手企業がPythonで大規模なワークロードを処理している事例からも分かるように、決して「遅い言語」ではありません。この記事では、正しく動作するPythonプログラムをさらに速く、効率的にするために押さえておきたい最適化のヒントを11個紹介します。
ヒント1: 組み込み関数を活用する
Pythonで独自に効率的なコードを書くことも可能ですが、C言語で実装された組み込み関数の速度には到底及びません。利用可能な組み込み関数はdir(__builtins__)で一覧表示できるので、車輪の再発明をする前に必ず確認しましょう。
ヒント2: 変数の入れ替えには多重代入を使う
変数の値を交換する際は、一時変数を使う代わりにPythonの多重代入を利用しましょう。
>>> # 一時変数を使う方法(遅い) >>> temp = x >>> x = y >>> y = temp >>> # 多重代入を使う方法(速い) >>> x, y = y, x
ヒント3: グローバル変数を避け、可能な限りローカル変数を使う
Pythonでは、グローバル変数へのアクセスよりもローカル変数へのアクセスの方が高速です。グローバル変数の使用はできるだけ避けましょう。
ヒント4: メンバーシップ判定には「in」を使う
要素の存在確認には「in」キーワードを使用しましょう。コードがすっきりし、処理も高速です。
for key in sequence:
print("Hello ", key)
ヒント5: 無限ループには「while 1」を使う
リスニングソケットなど、プログラムで無限ループが必要になる場面があります。「while True」でも同じ動作をしますが、「while 1」は単一のジャンプ命令になるため、より高速に動作します。
>>> while 1:
# 何かの処理(while 1の方が高速)
>>> while True:
# 同じ処理だが、上記よりやや遅い
ヒント6: リスト内包表記を使う
Python 2.0以降で使えるリスト内包表記は、多くの「for」や「while」ブロックを置き換えられます。インタプリタがループ中の予測可能なパターンを検出できるよう最適化されているため、はるかに高速です。可読性も高く、カウンタ用の余分な変数も不要になります。
例えば、1〜25の間の偶数を1行で求めるコードは以下の通りです。
>>> # リスト内包表記を使う方法(良い例)
>>> print([i for i in range(25) if i % 2 == 0])
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]
# 通常のループを使う方法(非効率)
i = 0
evens = []
while i < 25:
if i % 2 == 0:
evens.append(i)
i += 1
print(evens)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]
ヒント7: 必要なときに値を生成するジェネレータを使う
Pythonのジェネレータを使うとメモリを節約でき、パフォーマンスも向上します。例えば動画のストリーミング配信では、ストリーム全体ではなくバイト列のチャンク単位で送信できます。
>>> chunkBytes = (1000 * i for i in range(1000)) >>> next(chunkBytes) 0 >>> next(chunkBytes) 1000 >>> next(chunkBytes) 2000 >>> next(chunkBytes) 3000
ヒント8: itertoolsモジュールを使う
itertoolsモジュールは、イテレーションや組み合わせの処理において非常に有用かつ効率的です。
リスト [1, 2, 3, 4] のすべての順列を、わずか数行のPythonコードで生成できます。
>>> import itertools >>> iter1 = itertools.permutations([1, 2, 3, 4]) >>> list(iter1) [(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2), (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1), (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1), (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)]
ヒント9: ソート済みリストの維持にはbisectモジュールを使う
bisectモジュールは、無料で使える二分探索の実装であり、ソート済みシーケンスへの高速な挿入ツールです。
>>> import bisect >>> bisect.insort(list, element)
この方法で要素を挿入すれば、コンテナをソート済みの状態に保つために再度sort()を呼び出す必要がありません。長いシーケンスに対するsort()の呼び出しは非常にコストが大きくなります。
ヒント10: 辞書とセットでメンバーシップ判定を行う
辞書とセットはハッシュテーブルで実装されているため、Pythonでは要素の存在確認が非常に高速です。ルックアップはO(1)で完了することもあります。
>>> lst = ['a', 'ab', 'abc'] # 遅い:リストでの存在確認 >>> 'abc' in lst True >>> mySet = set(['a', 'ab', 'abc']) # 速い:セットや辞書での存在確認 >>> 'abc' in mySet True
ヒント11: デコレータで結果をキャッシュする
Pythonのデコレータは「@」記号で表されます。デコレータはトレース、ロック、ログ取得だけでなく、後で必要になる結果を関数に記憶させる(メモ化)ためにも使えます。
>>> from functools import wraps
>>> def memo(f):
cache = {}
@wraps(f)
def wrap(*arg):
if arg not in cache:
cache[arg] = f(*arg)
return cache[arg]
return wrap
このデコレータはフィボナッチ関数にも適用できます。
>>> @memo
def fib(i):
if i < 2:
return 1
return fib(i-1) + fib(i-2)
基本的な考え方は、計算済みのフィボナッチ数を関数に記憶させることです。キャッシュに存在する値は再計算せずに済むため、再帰処理の大幅な高速化が期待できます。
-
WordPressサイトの画像を最適化する7つの実践テクニック【表示速度とSEO改善】
画像は、質の高いWebサイトを構成する最も重要な要素のひとつです。訪問者の注意を引きつけ、コンテンツの拡散を促し、商品購入などの行動へとユーザーを導く力を持っています。 しかし、高解像度の画像やファイルサイズの大きな画像をそのまま使うと、ページの表示速度が低下し、ユーザー体験を大きく損なってしまいます。画質を目立って劣化させることなく画像を圧縮できるツールが数多く存在する今、表示速度の遅さを放置することは言い訳できません。 この記事では、Web、とりわけWordPressサイトで画像を最適化するための具体的な方法を紹介します。 1. 適切なファイル形式を選ぶ Webで最もよく使われて
-
マーケティング担当者必見!App Store最適化(ASO)を成功させる5つのヒント
スマートフォンの進化とともに、アプリビジネスは大きなブームを迎えました。アプリがない状態のスマートフォンは、単なる普通のデバイスと変わりません。しかし幸いなことに、多彩なアプリを搭載することでスマートフォンでできることは格段に広がり、日々のタスクも簡単にこなせるようになりました。航空券の予約からお気に入りのホテルの手配まで、あらゆる用途に対応するアプリが存在します。現在、毎日何百万ものアプリがApp Storeに追加されており、特にアプリ開発者にとって競争は日々激化の一途をたどっています。検索エンジンでは、ユーザーの多くが画面に表示された上位の検索結果しかクリックしないように、App Stor