web-dev-qa-db-ja.com

Pythonをマシンコードにコンパイルすることは可能ですか?

Python(おそらく中間C表現を介して)をマシンコードにコンパイルすることはどの程度実現可能でしょうか?

おそらく、Pythonランタイムライブラリと、Python標準ライブラリであるPythonそれ自体もコンパイル(およびリンク)する必要があります。

また、式の動的評価を行いたい場合はPythonインタープリターをバンドルする必要がありますが、これを許可しなかったPythonのサブセットそれでも有用です。

速度やメモリ使用量の利点はありますか?おそらくPythonインタープリターの起動時間はなくなります(ただし、共有ライブラリーは起動時にロードする必要があります)。

121
Andy Balaam

ShedSkin Python-to-C++コンパイラを試してみてください。しかし、完璧とはほど遠いです。また、Psycoがあります-Python高速化のみが必要な場合はJITです。しかし、私見ではこれは努力する価値はありません。 。

28
cleg

@Greg Hewgillが言うように、これが常に可能とは限らないのには十分な理由があります。ただし、特定の種類のコード(非常にアルゴリズム的なコードなど)は、「実際の」マシンコードに変換できます。

いくつかのオプションがあります。

  • Psyco を使用します。これは、マシンコードを動的に出力します。ただし、変換するメソッド/関数は慎重に選択する必要があります。
  • Cython を使用します。これはPython-like言語で、Python C拡張
  • PyPy を使用します。これにはRPythonからのトランスレーターがありますPython thatの制限されたサブセット Pythonの最も「動的な」機能の一部をCまたはLLVMにサポートしていません。
    • PyPyはまだ非常に実験的です
    • すべての拡張機能が存在するわけではありません

その後、既存のパッケージ(freeze、Py2exe、PyInstaller)のいずれかを使用して、すべてを1つのバイナリに入れることができます。

全体として、あなたの質問に対する一般的な答えはありません。 Pythonパフォーマンスが重要なコードがある場合は、できるだけ多くの組み込み機能を使用してみてください(または、「Pythonそれが解決しない場合は、コードを特定してC(またはCython)に移植し、拡張機能を使用してみてください。

51
Torsten Marek

py2c( http://code.google.com/p/py2c )は、pythonコードをc/c ++に変換できます。私はpy2cのソロ開発者です。

17
Ramchandra Apte

Nuitka は、Python libpythonにリンクするC++コンパイラです。比較的新しいプロジェクトのようです。著者は、 速度の改善 pystoneベンチマークでCPythonを介して。

14
bcattle

PyPy は、実装戦略の1つとしてネイティブコードへのコンパイルを使用して、PythonでPythonを再実装するプロジェクトです(JITを使用するVMはJVMを使用します)など)。コンパイルされたCバージョンは平均してCPythonよりも低速ですが、一部のプログラムでははるかに高速です。

Shedskin は実験的なPython-to-C++コンパイラです。

Pyrex は、Python拡張モジュールを作成するために特別に設計された言語です。ニースの高レベルで使いやすいPythonの世界と乱雑な低レベルのCの世界との間のギャップを埋めるように設計されています。

14
pdc

Pyrex は、CにコンパイルされるPython言語のサブセットであり、Pythonの最初のビルド list comprehensions で行われました。主にラッパーを構築するために開発されましたが、より一般的なコンテキストで使用することができます Cython は、パイレックスのより積極的に維持されるフォークです。

これは一見合理的と思われるかもしれませんが、Pythonには多くのPythonランタイムのサポート。たとえば、ダックタイピングが思い浮かびます。Python読み取り入力はファイルまたはファイルのようなものをとることができます) オブジェクト、特定の操作(read()やreadline()など)をサポートしている限り、このタイプのサポートをCにマッピングするのに何が必要かを考えると、想像し始めますPythonランタイムシステムが既に行っていることの種類。

py2exe などのユーティリティがあり、Pythonプログラムとランタイムを単一の実行可能ファイルに(可能な限り)バンドルします。

9
Greg Hewgill

いくつかの追加の参照:

5

Jythonには、JVMバイトコードをターゲットとするコンパイラがあります。バイトコードは、Python言語そのものです!非常にクールです。アプリとともに配布されます。)

3

Python→11l→C++ transpiler を試してください。

2
tav

Psyco は一種のジャストインタイム(JIT)コンパイラーです。Python用の動的コンパイラーで、コードを2〜100倍高速に実行しますが、多くのメモリが必要です。

要するに、ソースを変更せずに既存のPythonソフトウェアをはるかに高速で実行しますが、Cコンパイラと同じようにオブジェクトコードにコンパイルしません。

2

答えは「はい、可能です」です。 Pythonコードを取得し、CPython APIを使用して同等のCコードにコンパイルしようとすることができます。実際には、それを行うPython2Cプロジェクトがありましたが、聞いたことがありませんそれについては長年(Python 1.5日は私が最後に見たときに戻っています。)

PythonコードをできるだけネイティブCに変換し、実際のPython機能が必要な場合はCPython APIにフォールバックできます。私は先月または2か月間、そのアイデアをいじっていましたが、それは非常に多くの作業であり、膨大な量のPython機能をC:入れ子関数に変換するのは非常に困難です、ジェネレータ、シンプルなメソッドを備えたシンプルなクラス以外、モジュールの外部からモジュールグローバルを変更することなどが含まれます。

2
Thomas Wouters

これは、マシンコードにPythonをコンパイルしません。ただし、Pythonコードを呼び出すための共有ライブラリを作成できます。

探しているのが、execpに依存せずにCからPythonコードを実行する簡単な方法である場合。python code wrapped Python埋め込みAPI を数回呼び出すだけです。アプリケーションは共有ライブラリであり、他の多くのライブラリ/アプリケーションで使用できる.soです。

Cプログラムとリンクできる共有ライブラリを作成する簡単な例を次に示します。共有ライブラリはPythonコードを実行します。

実行されるpythonファイルは_pythoncalledfromc.py_:

_# -*- encoding:utf-8 -*-
# this file must be named "pythoncalledfrom.py"

def main(string):  # args must a string
    print "python is called from c"
    print "string sent by «c» code is:"
    print string
    print "end of «c» code input"
    return 0xc0c4  # return something
_

python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO')で試すことができます。出力されます:

_python is called from c
string sent by «c» code is:
HELLO
end of «c» code input
_

共有ライブラリは、_callpython.h_によって次のように定義されます。

_#ifndef CALL_PYTHON
#define CALL_PYTHON

void callpython_init(void);
int callpython(char ** arguments);
void callpython_finalize(void);

#endif
_

関連する_callpython.c_は次のとおりです。

_// gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <python2.7/Python.h>

#include "callpython.h"

#define PYTHON_EXEC_STRING_LENGTH 52
#define PYTHON_EXEC_STRING "import pythoncalledfromc; pythoncalledfromc.main(\"%s\")"


void callpython_init(void) {
     Py_Initialize();
}

int callpython(char ** arguments) {
  int arguments_string_size = (int) strlen(*arguments);
  char * python_script_to_execute = malloc(arguments_string_size + PYTHON_EXEC_STRING_LENGTH);
  PyObject *__main__, *locals;
  PyObject * result = NULL;

  if (python_script_to_execute == NULL)
    return -1;

  __main__ = PyImport_AddModule("__main__");
  if (__main__ == NULL)
    return -1;

  locals = PyModule_GetDict(__main__);

  sprintf(python_script_to_execute, PYTHON_EXEC_STRING, *arguments);
  result = PyRun_String(python_script_to_execute, Py_file_input, locals, locals);
  if(result == NULL)
    return -1;
  return 0;
}

void callpython_finalize(void) {
  Py_Finalize();
}
_

次のコマンドでコンパイルできます:

_gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so
_

次を含む_callpythonfromc.c_という名前のファイルを作成します。

_#include "callpython.h"

int main(void) {
  char * example = "HELLO";
  callpython_init();
  callpython(&example);
  callpython_finalize();
  return 0;
}
_

コンパイルして実行します:

_gcc callpythonfromc.c callpython.so -o callpythonfromc
PYTHONPATH=`pwd` LD_LIBRARY_PATH=`pwd` ./callpythonfromc
_

これは非常に基本的な例です。動作しますが、ライブラリによっては、Cデータ構造をPythonおよびfrom Python to Cにシリアル化することは依然として困難です。 ...

Nuitka が役立つ場合があります。

また、 numba がありますが、どちらもあなたが望むことを正確に行うことを目指していません。 PythonコードからCヘッダーを生成できますが、PythonタイプをCタイプに変換する方法を指定するか、その情報を推測できます。 python astroid Python astアナライザーの場合。

2
amirouche