Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonコードが関数内でより高速に実行されるのはなぜ?理由を徹底解説

Pythonのコードを通常どおり実行した場合と、関数の中で実行した場合を比較すると、後者の方が高速に動作することが知られています。では、なぜPythonコードは関数内でより速く実行されるのでしょうか。本記事ではその理由をわかりやすく解説します。

ローカル変数はグローバル変数より高速

一般的に、Pythonの関数内では、グローバル変数よりもローカル変数を扱う方が高速であることが分かっています。この違いは、次のように説明できます。

ローカル変数とグローバル変数の格納・読み出しにかかる時間の差に加えて、「オペコード予測(opcode prediction)」と呼ばれる仕組みも、関数の実行を高速化する大きな要因となっています。

CPythonの仕組み

CPythonとは、Python.orgからダウンロードできるオリジナルのPython実装のことです。後に登場した他のPython実装(PyPyやJythonなど)と区別するため、また言語エンジンの実装とPythonというプログラミング言語そのものを区別するために、CPythonという名前が使われています。

CPythonはC言語で実装されており、私たちが書いたPythonコードをまずバイトコードにコンパイルし、そのバイトコードを評価ループ(evaluation loop)の中で解釈しながら実行します。

ローカル変数が高速な技術的な理由

関数がコンパイルされる際、ローカル変数は固定サイズの配列(辞書ではありません)に格納され、各変数名にはインデックスが割り当てられます。これは、関数のローカル変数を動的に追加することができないため実現できる仕組みです。

その結果、ローカル変数の取得は、リストへの単純なポインタ参照と、PyObjectの参照カウントを1つ増やす処理だけで完了します。このコストはほぼ無視できるレベルです。

一方、グローバル変数の検索は、ハッシュ計算などを伴う本物の辞書(dict)検索になります。この違いが、両者の速度差の主な原因です。

globalキーワードが必要な理由

ちなみに、この仕組みこそが、変数をグローバルとして扱いたい場合にglobalキーワードを指定する必要がある理由でもあります。スコープ内で変数に代入を行うと、明示的に指示しない限り、コンパイラはその変数へのアクセスに対してSTORE_FAST命令を発行するためです。

まとめ

とはいえ、グローバル変数の検索自体もかなり最適化されています。本当に処理が遅くなるのは、むしろ属性(アトリビュート)の参照です。パフォーマンスを意識する場合は、ループ内などで頻繁にアクセスする値をあらかじめローカル変数にキャッシュしておくと、効果的に処理を高速化できるでしょう。

  1. Pythonのissubset()関数とは?部分集合の判定方法を実例付きで解説

    本記事では、Python標準ライブラリに用意されているissubset()関数の仕組みと使い方について詳しく解説します。 issubset()メソッドは、あるセット(集合)のすべての要素が、引数として渡した別のセットにも含まれている場合にブール値のTrueを返し、1つでも含まれていない要素があればFalseを返します。 下の図では、BはAの部分集合です。もしAとBが同一のセットであれば、両者は互いに部分集合の関係にあるといえます。つまり、両方のセットがまったく同じ要素を持っているということを意味します。 構文 <set 1>.issubset(<set 2>) 戻り値

  2. なぜPythonは他の言語より遅いのか?実行速度の違いを徹底解説

    Pythonはスクリプト言語であり、Cはコンパイル型のプログラミング言語です。C/C++がPythonと比べて高速なのは、この実行方式の違いによるものです。Pythonスクリプトを実行する場合、インタプリタがコードを1行ずつ解釈しながら出力を生成します。一方、Cでは事前にコンパイラがソースコードをコンパイルし、ハードウェアに最適化された実行ファイルを生成します。また、Javaや.NETなどの言語では、JIT(Just-In-Time)コンパイラが実行時にバイトコードをネイティブコードへ変換するため、Javaバイトコードや.NETバイトコードはPythonよりも高速に動作します。CPythonに