Pythonが解釈される場合、.pycファイルとは何ですか?


1084

Pythonはインタプリタ言語であることを理解するために与えられました...
しかし、Pythonソースコードを見ると.pyc、Windowsが「コンパイルされたPythonファイル」と識別するファイルが表示されます。

これらはどこから来るのですか?


3
正当化については、stackoverflow.com / questions / 11433579 /…を参照してください。一言で言えば、スピード。
user7610 2015



Pythonでさえ、Javaと同じように「1度書き込み、どこでも実行できる」ということですか?
Mrak Vladar

2
@MrakVladar Javaでさえ、「1回の書き込みでどこでも実行できます(JVMがある場合)」。Pythonも同じです。「Python仮想マシンがあればどこでも実行できます」。大きな違いは、ほとんどのPythonの実装はかなりのようにそれらを分離するよりも、1つの実行ファイルにコンパイラとインタプリタを兼ね備えていることであるjavajavac
chepner

回答:


660

それらには、Pythonインタープリターがソースをコンパイルするバイトコードが含まれています。このコードは、Pythonの仮想マシンによって実行されます。

Pythonのドキュメントでは、次のように定義を説明しています。

コンパイルされたものとは対照的に、Pythonはインタプリタ言語ですが、バイトコードコンパイラが存在するため、区別がぼやけることがあります。これは、実行可能ファイルを明示的に作成せずにソースファイルを直接実行できることを意味します。


10
興味深い、ありがとう。では、Pythonは純粋に解釈された言語と見なされているのでしょうか?
froadie

194
@froadie:言語はそのように「解釈」または「コンパイル」されていません。特定の実装では、インタープリタまたはコンパイラ(またはハイブリッドまたはJITコンパイラ)であることができます。
Joachim Sauer

30
「コンパイル済み」の1つのテスト:実際の機械語命令にコンパイルされていますか?Pythonバイトコードは機械命令ではなく、Javaの「JVM」命令でもないため、これらの言語はどちらもその定義でコンパイルされていません。しかし、どちらも中間の「抽象マシン」コードに「コンパイル」され、どちらもソースコードを直接解釈することでプログラムを実行するよりもはるかに高速です(これは昔ながらのBASICが行うことです)。
greggo 2013

20
簡潔に言うと、「コンパイル済み」は「翻訳済み」を意味します。次に、Pythonがバイトコードにコンパイルされます。私の知る限り、実際に 解釈されるのはBashだけです他のすべての一般的な「解釈済み」言語はすべてバイトコードにコンパイルされます。
bfontaine 14

13
実際、これらマシン命令であり、ホストの物理CPUのネイティブマシン命令ではありません。それで、なぜそれをVMと呼ぶのですか?アセンブリ言語のエスペラントのように。最近では、架空の(ただしエミュレートされた)CPU(子供に興味を持ってもらうためのMojangの取り組み)のネイティブコードさえあります。Rexxは本当に解釈された(または解釈された可能性がある)、BATおよびCMD(およびDCL)が解釈されます。
mckenzm 2014

994

Pythonがインタプリタ言語であることを理解するために与えられました...

この人気のミームは正しくない、または(自然な)言語レベルの誤解に基づいて構築されています。同様の間違いは、「聖書はハードカバーの本です」と言うことです。その類似点を説明しましょう...

「聖書」とは、(実際に存在する、物理的な対象物として識別される)本のクラスという意味の「本」です。「聖書のコピー」として識別された本は、基本的な共通点があると思われます(内容は、異なる言語であっても、許容される翻訳、脚注のレベル、およびその他の注釈が異なる場合があります)-ただし、これらの本は基本とは見なされない無数の側面で完全に異なることが許可されています-綴じの種類、綴じの色、印刷に使用されるフォント、ある場合はイラスト、書き込み可能な余白が広いかどうか、組み込みブックマークの数と種類など。

聖書の典型的な印刷が実際にハードカバーの製本である可能性はかなりあります-結局のところ、それは通常、何度も何度も読まれ、いくつかの場所でブックマークされ、与えられた章と節へのポインタを探すことでつまづかれる本です。など、そして適切なハードカバーの綴じ方は、そのような使用下で所定のコピーをより長く持続させることができます。ただし、これらはありふれた(実用的な)問題であり、特定の実際の書籍オブジェクトが聖書のコピーであるかどうかを判断するために使用することはできません。ペーパーバック印刷は完全に可能です!

同様に、Pythonは言語実装のクラスを定義するという意味で「言語」であり、基本的な点(構文、明示的に異なることが許可されている部分以外のほとんどのセマンティクス)はすべて類似している必要がありますが、完全に許可されています。与えられたソースファイルの扱い方、ソースをいくつかの低レベルフォームにコンパイルするかどうか(そうであれば、どのフォームか)、およびそれらを保存するかどうかなど、ほぼすべての「実装」の詳細を変えるコンパイルされたフォーム、ディスクまたはその他の場所)、フォームの実行方法など。

古典的な実装であるCPythonは、略して単に「Python」と呼ばれることが多いですが、MicrosoftのIronPython(CLRコード、つまり「.NET」にコンパイルされる)、Jythonと並んで、いくつかの製品品質の実装の1つにすぎません。 (JVMコードにコンパイル)、PyPy(Python自体で記述され、「ジャストインタイム」で生成されたマシン言語を含む非常に多様な「バックエンド」フォームにコンパイルできます)。これらはすべて、Python(== "Python言語の実装")であり、表面的に異なる多くの本のオブジェクトがすべて聖書(== "Thecopible of the Bible")であるのと同じです。

特にCPythonに興味がある場合:ソースファイルをPython固有の下位レベルのフォーム(「バイトコード」と呼ばれる)にコンパイルし、必要に応じて(ソースファイルに対応するバイトコードファイルがない場合、またはバイトコードファイルはソースよりも古いか、別のPythonバージョンでコンパイルされています)。通常、バイトコードファイルをディスクに保存します(将来再コンパイルされないようにするため)。OTOH IronPythonは通常、CLRコード(ディスクに保存するかどうかに応じて)にコンパイルし、JythonをJVMコード(ディスクに.class保存するかどうか)にコンパイルします。保存する場合は、拡張機能を使用します。

これらの下位レベルのフォームは、「インタープリター」とも呼ばれる適切な「仮想マシン」(CPython VM、.Netランタイム、Java VM(別名JVM))によって適切に実行されます。

したがって、この意味で(典型的な実装は何をするのか)、Pythonは「解釈された言語」であり、C#とJavaがそうである場合に限り、それらすべてに、最初にバイトコードを生成し、次にVM /インタープリターを介して実行するという典型的な実装戦略があります。 。

おそらくフォーカスは、コンパイルプロセスがいかに「重く」、遅く、ハイセレモニーであるかです。CPythonは、可能な限り少ない式で、可能な限り高速に、可能な限り軽量にコンパイルするように設計されています-コンパイラーはエラーチェックと最適化をほとんど行わないため、高速かつ少量のメモリで実行できるため、ほとんどの場合、ユーザーはコンパイルが行われていることを意識する必要さえなく、必要なときにいつでも自動的かつ透過的に実行されます。エラーをより徹底的にチェックし、より多くの最適化を実行するために、JavaおよびC#は通常、コンパイル中により多くの作業を受け入れます(したがって、自動コンパイルを実行しません)。連続したグレースケールであり、黒や白の状況ではありません。


2
美しい答え。最後の段落のほんの少しの訂正:Pythonは可能な限り高速にコンパイルできるように設計されています(など)。今回は、静的な型システムやその他のものが欠けている、本当に言語です。人々が「解釈された」言語について話すとき、それらは通常「動的な」言語を意味します。
Elazar

1
@Elazar、実際にはPyPyなどの他のPythonの実装はコンパイルが急がず、静的型付けの欠如によって要求されるより徹底的な分析を行い、マシンコードへのジャストインタイムコンパイルを生成します(したがって高速化)実行時間の長いプログラムを何度も起動します)。
Alex Martelli、2015

Cythonはここにどこに収まりますか?別の言語だと思いますか、それともPythonの実装ですか?また、PythonのVMは「インタプリタ」と呼ばれることが多いため、この「解釈済み」と「コンパイル済み」のミームは、おそらく単なる用語の混乱なのでしょうか。JVMまたは.NETランタイムインタープリターを呼び出すことも同様に有効です。どちらもほとんどがバイトコードをJITマシンコードに解釈します(一部のキャッシュ最適化の例外はあります)
Davos

181

インタプリタ言語のようなものはありません。インタープリターが使用されるかコンパイラーが使用されるかは、純粋に実装の特性であり、言語とはまったく関係がありません。

すべての言語は、インタープリターまたはコンパイラーによって実装できます。大多数の言語には、各タイプの実装が少なくとも1つあります。(たとえば、CとC ++にはインタープリターがあり、JavaScript、PHP、Perl、Python、Rubyにはコンパイラーがあります。)さらに、現代の言語実装の大部分は、インタープリターとコンパイラー(または複数のコンパイラー)の両方を実際に組み合わせています。

言語は抽象的な数学的なルールのセットです。インタプリタは、言語のいくつかの具体的な実装戦略の1つです。これら2つは、完全に異なる抽象化レベルにあります。英語が型付き言語である場合、「解釈された言語」という用語は型エラーになります。「Pythonはインタプリタ言語です」という文は単にfalseであるわけではありません(falseであることは、文が間違っていても意味があることを意味するため)、言語を次のように定義することはできないため、単純に意味がありません。「解釈された」

特に、現在存在するPythonの実装を見てみると、これらは使用している実装戦略です。

  • IronPython:DLRがCILバイトコードにコンパイルされるDLRツリーにコンパイルされます。CILバイトコードがどうなるかは、実行しているCLI VESによって異なりますが、Microsoft .NET、GNU Portable.NET、およびNovell Monoは、最終的にそれをネイティブマシンコードにコンパイルします。
  • Jython:ホットコードパスが特定されるまでPythonソースコードを解釈し、それをJVMLバイトコードにコンパイルします。JVMLバイトコードがどうなるかは、実行しているJVMによって異なります。Maxineは、ホットコードパスを識別して最適化されたネイティブコードに再コンパイルするまで、最適化されていないネイティブコードに直接コンパイルします。HotSpotは最初にJVMLバイトコードを解釈し、次に最終的にホットコードパスをコンパイルして最適化されたマシンコードにします。
  • PyPy:PyPyバイトコードにコンパイルされます。次に、実行しているプラ​​ットフォームに応じてネイティブコード、JVMLバイトコード、またはCILバイトコードにコンパイルされるホットコードパスを識別するまで、PyPy VMによって解釈されます。
  • CPython:CPythonバイトコードにコンパイルしてから解釈します。
  • スタックレスPython:CPythonバイトコードにコンパイルしてから解釈します。
  • Unladen Swallow:CPythonバイトコードにコンパイルし、ホットコードパスを識別してLLVM IRにコンパイルし、LLVMコンパイラーがネイティブマシンコードにコンパイルするまで解釈します。
  • Cython:PythonコードをポータブルCコードにコンパイルし、標準のCコンパイラでコンパイルします。
  • Nuitka:Pythonコードをマシン依存のC ++コードにコンパイルし、標準のCコンパイラでコンパイルします

リストの実装のすべて(tinypy、Shedskin、Psycoなど、私が言及しなかった他の実装も)にはコンパイラーがあることに気付くでしょう。実際、私が知る限り、現時点では純粋に解釈されるPython実装はなく、そのような実装は計画されておらず、そのような実装はこれまでありません。

「解釈された言語」という用語が意味をなさないだけでなく、「解釈された実装の言語」を意味すると解釈しても、それは明らかに真実ではありません。誰が言ったのか、彼が何について話しているのかは明らかにわかりません。

特に、表示.pycされているファイルは、CPython、Stackless Python、またはUnladen Swallowによって生成されたキャッシュされたバイトコードファイルです。


5
MSBASICなどの昔ながらのベーシックには中間形式はありませんでした。プログラムは、ソースフォーム(またはニアソース)から直接解釈されました。キーワードは1バイトのトークンで表され、行番号は2バイトのバイナリ整数で表されますが、残りはASCIIでした)。したがって、実際には「goto」は、一致する宛先を探すために検索する必要があるソース行の数に応じて、異なる時間がかかります。a * b-2 * cos(x)のような式は、実行されるたびに効果的に再解析されました。
greggo 2013

4
@greggo:そして、もっと古い学校に行きたいのであれば、BASIC のオリジナルバージョンはネイティブコードコンパイラでした。これは、「コンパイルされた」または「解釈された」言語の概念がいかにばかげているかを証明するはずです。
イェルクWミッターク

さまざまなpythonコンパイラー/インタープリターの動作を説明していただきありがとうございます。効率的なCまたはJavaScriptを生成する優れたPythonコンパイラはまだあるのでしょうか。それは非常に実行可能で、大量消費ではないかもしれませんが、少なくともPythonの合理的なサブセットでは可能です。また、サイソンって何なんだろう。
personal_cloud

CythonはSciPy 2009で言及されましたが、2010年にはそのことを知らなかったことを許してもかまいません(ここで私は2017年になって今、それについて学んでいます)。それでもJavaScriptの例を見つける必要があります... Jythonは私には意味がありません(Javaは2009年までにすでに死んでいましたか?ええと、ええと、おそらくC ++のブーストはそれほど良くありませんでした)
personal_cloud

1
@personal_cloud:私はあなたのコメントを完全にはフォローしていません。はい、もちろん、私はCythonについて知っていますが、それは何かとどう関係しているのですか?Pythonの実装ではなく、完全に異なる言語です。また、JavaScriptの例を見つけることは実際には難しくありません。実際、現在存在するすべての主流のJavaScript実装にはコンパイラーがあります。最後に、Jythonは、Pythonの他の実装と同様にPythonの実装です。また、Javaプラットフォーム上の他の言語実装と同様に、Javaプラットフォーム上の言語の実装です。
イェルクWミッターク

61

これらは、.pyファイルのインポート時にPythonインタープリターによって作成され、インポートされたモジュール/プログラムの「コンパイル済みバイトコード」が含まれます。つまり、ソースコードからバイトコードへの「変換」は1回だけ実行する必要があります。が対応するファイルよりも新しいimport場合、後続のでスキップできます。これにより、起動が少し速くなります。しかし、それはまだ解釈されています。.pyc.py


10
本当です。多くのコアPythonライブラリがCで書かれていることを除いて、Pythonの一部は解釈され、一部はCで実行されます。パフォーマンスに依存する独自のコードに対しても同じことができます。
bwawok

44

モジュールのロードを高速化するために、Pythonはモジュールのコンパイル済みコンテンツを.pycにキャッシュします。

CPythonはソースコードを「バイトコード」にコンパイルします。パフォーマンス上の理由から、ソースファイルに変更があった場合は常に、このバイトコードをファイルシステムにキャッシュします。これにより、コンパイルフェーズをバイパスできるため、Pythonモジュールの読み込みがはるかに高速になります。ソースファイルがfoo.pyの場合、CPythonはバイトコードをソースのすぐ隣のfoo.pycファイルにキャッシュします。

python3では、Pythonのインポート機構が拡張されて、すべてのPythonパッケージディレクトリ内の単一のディレクトリでバイトコードキャッシュファイルの書き込みと検索が行われます。このディレクトリは__pycache__と呼ばれます。

以下は、モジュールのロード方法を説明するフローチャートです。

ここに画像の説明を入力してください

詳細については:

ref:PEP3147
ref:「コンパイルされた」Pythonファイル


38

これは初心者向けです

Pythonは、スクリプトを実行する前に、スクリプトをコンパイルされたコード(いわゆるバイトコード)に自動的にコンパイルします。

スクリプトの実行はインポートとは見なされず、.pycは作成されません。

スクリプトファイルがある場合たとえば、abc.pyその輸入、別のモジュールxyz.pyを使用すると、実行すると、abc.pyxyz.pycは XYZがインポートされるために作成されますが、ないabc.pycファイルがされます作成されていない ABC以来。 pyはインポートされていません。

インポートされていないモジュールの.pycファイルを作成する必要がある場合は、py_compileおよびcompileallモジュールを使用できます。

py_compileモジュールは任意のモジュールを手動でコンパイルできます。1つの方法はpy_compile.compile、そのモジュールの関数をインタラクティブに使用することです。

>>> import py_compile
>>> py_compile.compile('abc.py')

これにより、.pycがabc.pyと同じ場所に書き込まれます(オプションのパラメーターで上書きできますcfile)。

compileallモジュールを使用して、ディレクトリ内のすべてのファイルを自動的にコンパイルすることもできます。

python -m compileall

ディレクトリ名(この例では現在のディレクトリ)を省略した場合、モジュールは、 sys.path


6
そして、abc.pyを取得するためにコンパイルする利点は何ですか?
Saher Ahwal 2017

@SaherAhwal考えられる利点の1つは、構文チェックです。
Yi Bao

20

Python(少なくとも最も一般的な実装)は、元のソースをバイトコードにコンパイルしてから、仮想マシンでバイトコードを解釈するパターンに従います。これは(繰り返しますが、最も一般的な実装)は、純粋なインタプリタでもコンパイラでもありません。

ただし、これとは逆に、コンパイルプロセスはほとんど隠されています-.pycファイルは基本的にキャッシュのように扱われます。彼らは物事をスピードアップしますが、あなたは通常それらをまったく意識する必要はありません。必要に応じて、ファイルの時刻/日付スタンプに基づいて、それらを自動的に無効にして再ロードします(ソースコードを再コンパイルします)。

この問題が発生したのは、コンパイルされたバイトコードファイルが何らかの形で将来のタイムスタンプを取得したときだけでした。つまり、常にソースファイルよりも新しく見えました。見た目が新しくなったため、ソースファイルは再コンパイルされなかったため、どのような変更を加えても無視されました...


12

Pythonの* .pyファイルは、テキストファイルであり、そこにコード行を記述します。「python filename.py」と言ってこのファイルを実行しようとすると

このコマンドは、Python仮想マシンを呼び出します。Python仮想マシンには、「コンパイラ」と「インタプリタ」の2つのコンポーネントがあります。インタープリターは* .pyファイル内のテキストを直接読み取ることができないため、このテキストは最初にPVM (ハードウェアではなくPVM)をターゲットとするバイトコードに変換されます。PVMはこのバイトコードを実行します。* .pycファイルは、シェルまたは他のファイルでインポート操作を実行する実行の一部としても生成されます。

この* .pycファイルがすでに生成されている場合、次に* .pyファイルを実行/実行するたびに、システムはコンパイルを必要としない* .pycファイルを直接ロードします(これにより、プロセッサのマシンサイクルがいくらか節約されます)。

* .pycファイルが生成されたら、編集しない限り、*。pyファイルは必要ありません。


7

Pythonコードは2つの段階を経ます。最初のステップは、コードを実際にバイトコードである.pycファイルにコンパイルします。次に、この.pycファイル(バイトコード)はCPythonインタープリターを使用して解釈されます。このリンクを参照しください。ここでは、コードのコンパイルと実行のプロセスを簡単に説明します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.