web-dev-qa-db-ja.com

Pythonコンパイラが必要ないのはなぜですか?

なぜPythonはコンパイラを必要としないC++から始めたのでしょうか)

コードを入力して、execとして保存し、実行するだけです。 C++では、ビルドやその他すべての楽しいものを作成する必要があります。

29
Billjk

Pythonにはコンパイラがあります!自動的に実行されるため、気付かないだけです。ただし、そこにあることがわかります。importのモジュール用に生成された.pyc(またはオプティマイザがオンになっている場合は.pyo)ファイルを確認してください。

また、ネイティブマシンのコードにコンパイルされません。代わりに、仮想マシンで使用されるバイトコードにコンパイルされます。仮想マシンはそれ自体がコンパイルされたプログラムです。これは、Javaが機能する方法に非常に似ています。実際には、Pythonバリアント( Jython ) Java代わりに仮想マシンのバイトコードにコンパイルされます! IronPython もあり、MicrosoftのCLR(.NETで使用)にコンパイルされます(通常のPythonバイトコードコンパイラは、CPythonと呼ばれることもあります。

言語自体が不完全であるため、C++はコンパイルプロセスを公開する必要があります。リンカがプログラムを構築するために知っておく必要があるすべてを指定しているわけではなく、コンパイルオプションを移植可能に指定しているわけでもありません(一部のコンパイラでは#pragmaを使用できますが、それは標準ではありません)。そのため、残りの作業はmakefileを使用して行う必要があります。これは、Cが行った方法のほんの一部です。そして、Cはコンパイラーを単純化したので、そのように行いました。これは、それが非常に人気がある主な理由の1つです(80年代には誰でも単純なCコンパイラーを作り出すことができました)。


コンパイラーまたはリンカーの操作に影響を与える可能性があるが、CまたはC++の構文内で指定されていないもの:

  • 依存関係の解決
  • 外部ライブラリの要件(依存関係の順序を含む)
  • オプティマイザレベル
  • 警告設定
  • 言語仕様バージョン
  • リンカマッピング(どのセクションが最終プログラムのどこに行くか)
  • ターゲットアーキテクチャ

これらのいくつかは検出できますが、指定することはできません。例えば__cplusplusでどのC++が使用されているかを検出できますが、コード自体の中でコードに使用されているのがC++ 98であることを指定できません。 Makefileでコンパイラにフラグとして渡すか、ダイアログで設定を行う必要があります。

コンパイラーには「依存関係解決」システムが存在し、依存関係レコードが自動的に生成されると考えるかもしれませんが、これらのレコードは、特定のソースファイルがどのヘッダーファイルを使用するかを示すだけです。実行可能プログラムにリンクするために必要な追加のソースコードモジュールを示すことはできません。これは、CまたはC++には、特定のヘッダーファイルが単なる束ではなく、別のソースコードモジュールのインターフェイス定義であることを示す標準的な方法がないためです。繰り返し表示しないように、複数の場所に表示したい線。ファイルの命名規則には慣例がありますが、これらはコンパイラやリンカーによって認識または強制されていません。

これらのいくつかは#pragmaを使用して設定できますが、これは非標準であり、私は標準について話していました。これらすべては標準で指定できますが、下位互換性の目的ではありませんでした。 makefileとIDEは壊れていないので、それらを修正しないでください。

Pythonはこのすべてを言語で処理します。たとえば、importは明示的なモジュール依存関係を指定し、依存関係ツリーを意味します。モジュールはヘッダーファイルとソースファイル(つまり、インターフェースと実装)に分割されません。

68
Mike DeSimone

Pythonはインタープリター型言語です。これは、Pythonコードを読み取り、マシンに「指示」を送信するソフトウェアがコンピューター上にあることを意味します。 解釈言語に関するウィキペディアの記事 は、興味。

C++(コンパイルされた言語)のような言語がコンパイルされると、それは実行時にハードウェアによって直接読み取られるマシンコードに変換されることを意味します。 コンパイル済み言語に関するウィキペディアの記事 は興味深い対照を提供するかもしれません。

7
Zenon

すべてのコンパイル済み言語に、編集、コンパイル、リンク、実行のサイクルがあるというわけではありません。

あなたが実行しているのは、C++(または少なくともC++実装)の機能/制限です。

何かを行うには、コードをファイルに保存し、リンクと呼ばれるプロセスによってモノリシックイメージを構築する必要があります。

特に、コンパイルと解釈の違いを誤解しているのは、このモノリシックリンクプロセスです。

一部の言語では、マシンコードへのコンパイルを排除するのではなく、ぎこちないモノリシックリンク手順を排除することにより、これらすべてをより動的に行います。ソースは引き続きオブジェクトファイルにコンパイルされますが、これらはモノリシック実行可能ファイルにリンクされるのではなく、ランタイムイメージにロードされます。

「このモジュールを再ロード」と言うと、ソースをロードして解釈するか、モードスイッチに応じてコンパイルします。

Cで作業している場合でも、Linuxカーネルプログラミングにはこのような特徴があります。モジュールを再コンパイルして、ロードおよびアンロードできます。もちろん、実行可能なものを生成していることに気づいていることはありますが、それは複雑なビルドシステムによって管理されており、手動の手順がいくつかあります。しかし、実際には、最終的にはその小さなモジュールだけをアンロードして再ロードでき、カーネル全体を再起動する必要はありません。

一部の言語では、これよりもさらに細かいモジュール化が行われており、ビルドとロードはランタイム内から行われるため、よりシームレスです。

5
Kaz

最初の質問からの転換点...言及されていない点は、pythonプログラムのソースは、ユーザーの観点から見ると、使用および配布するものであるということですISプログラム私たちは物事を、明確に定義されていないカテゴリーに単純化する傾向があります。

コンパイルされたプログラムは、通常、マシンコードのスタンドアロンファイルと見なされます。 (確かに、特定のオペレーティングシステムに関連付けられたダイナミックリンクライブラリへのリンクが含まれていることがよくあります)。これは...コンパイルまたは解釈されたものとして説明できるほとんどのプログラミング言語のバリエーションがあります。

Pythonは、作成するマシンコードを簡単にアクセスまたは配布できる形式で保存せずにコードをコンパイルおよび実行するアプリケーション(インタープリターと呼ばれる)に依存しているため、コンパイラーを必要としません。

2

すべてのプログラミング言語は、人間の概念からターゲットマシンコードへの変換を必要とします。アセンブリ言語でさえ、マシンコードに変換する必要があります。その変換は通常、次のフェーズで行われます。

フェーズ1:分析および中間コードへの変換(解析)。フェーズ2:外部参照用のプレースホルダーを使用して、中間コードをターゲットマシンコードに変換します。フェーズ3:外部参照の解決とマシン実行可能プログラムへのパッケージ化。

この変換は、しばしばプリコンパイルおよび「ジャストインタイム」(JIT)またはランタイムコンパイルと呼ばれます。

C、C++、COBOL、Fortran、Pascal(すべてではない)、アセンブリなどの言語は、インタープリターを必要とせずにオペレーティングシステムで直接実行できるプリコンパイル済み言語です。

Java、BASIC、C#、Python=などの言語は解釈されます。これらはすべて、フェーズ1で作成された中間コードを使用しますが、それをマシンコードに変換する方法が異なる場合があります。最も単純な形式では、期待される作業を実行するマシンコードルーチンを実行するための中間コード。中間コードをマシンコードにコンパイルし、実行時に外部依存関係を修正します。コンパイルすると、すぐに実行できます。また、マシンコードはキャッシュに保存されます。関数が後で再び必要になった場合に後で再利用できる、以前にコンパイルされた再利用可能なマシンコードの一部関数がすでにキャッシュされている場合、インタープリターは再度コンパイルする必要はありません。

最新の高水準言語のほとんどは、インタープリター付き(JIT付き)カテゴリーに分類されます。プリコンパイルされているのは、主にCやC++などの古い言語です。

1
Mark Baker