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


128

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

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

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

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


2
ところで、オブジェクトコードではなく「マシンコード」を要求した場合、私見はより明確になります。
Torsten Marek

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

回答:


31

ShedSkin Python-to-C ++コンパイラを試してみてください。スピードアップだけが必要な場合は、Psyco-Python JITもあります。しかし、私見これは努力する価値はありません。コードの速度が重要な部分の場合、最良の解決策は、それらをC / C ++拡張機能として記述することです。


5
ちなみに、ShedSkinはWindowsのサポートを終了しました。
ソリン2010

2
まあ、今日はそれが窓をサポートしています...:@sorin code.google.com/p/shedskin/downloads/...

2
最良の解決策は、速度的には、まだPyPyである可能性があります。
Cees Timmerman

shedskinは、約2年の間にそれで行われた仕事をしていません。:(
パーキンス

53

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

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

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

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

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


3
PypyはPsycoの後継です
bcattle 14

19

py2c(https://github.com/pradyun/Py2C)はpythonコードをc / c ++に変換できます私はpy2cのソロ開発者です。


これは便利なツールのようです。それはまだ維持されていますか?
アンダーソングリーン

@AndersonGreen私が最後に作業していたのは、初期の開発段階です(おそらく現在は同じです)。私は怠惰なので、プロジェクトを辞めました。「重要な」テキストに気付いていない場合は、GitHubに移動しました。
Ramchandra Apte 2014

リンクはunvanquished-installerを指していますが、これは別のプロジェクトのようです。py2cはまだGitHubで利用できますか?
アンダーソングリーン

@AndersonGreenわあ、長い間見過ごされていました。ここに行きます。
Ramchandra Apte 14

code.google.com/p/py2cのリンクはまだunvanquished-installerを指しているため、今すぐ更新する必要があります。
アンダーソングリーン

15

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

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

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


3
Cythonは、Pyrexのより広く使用され、より積極的に開発されたフレンドリーなフォークです。
マイクグラハム

「Pythonの高水準で使いやすい世界と、Cの乱雑で低水準の世界」-おかしいのは、Cとアセンブラが「素晴らしく」てシンプルで、Pythonが「乱雑」、「高水準」の世界
リバースエンジニア

14

Nuitkaは、libpythonにリンクするPythonからC ++へのコンパイラーです。比較的新しいプロジェクトのようです。著者は、pystoneベンチマークでCPythonよりも速度が向上したと主張しています。


10

一見するとこれは理にかなっているように見えるかもしれませんが、Pythonランタイムサポートの多くを引き継がずにC表現に直接マッピングできない多くの普通のことがPythonにあります。たとえば、アヒルのタイピングが頭に浮かびます。入力を読み取るPythonの多くの関数は、特定の操作をサポートしている限り、ファイルまたはファイルのようなオブジェクトをとることができます。read()またはreadline()。このタイプのサポートをCにマップするために何が必要かを考えると、Pythonランタイムシステムがすでに行っているようなことを正確に想像し始めます。

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


1
静的にコンパイルされた言語は(少なくとも私の考えでは)実行時に爆発する可能性が低いため、コードが確実にコンパイルされるようにすることが私の目標である場合はどうなりますか?呼び出されたときにないfoo.xため、一部の式が機能しないと判断することは可能ですか?Pythonの静的コードチェッカーはありますか?Pythonは.Netアセンブリにコンパイルできます...foox
Hamish Grubijan '20 / 10/20

10

Pyrexは、Pythonのリスト内包表記を最初に作成した人がCにコンパイルするPython言語のサブセットです。主にラッパーを構築するために開発されましたが、より一般的なコンテキストで使用できます。 Cythonは、より積極的に維持されているpyrexのフォークです。


2
Cythonは、Pyrexのより広く使用され、より積極的に開発されたフレンドリーなフォークです。
マイクグラハム、


3

Jythonには、JVMバイトコードをターゲットとするコンパイラーがあります。バイトコードは、Python言語自体のように完全に動的です!とてもかっこいい。(はい、Greg Hewgillの回答が示唆しているように、バイトコードはJythonランタイムを使用するため、Jython jarファイルをアプリとともに配布する必要があります。)


2

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

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


2

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

Pythonコードを可能な限りネイティブCに変換し、実際のP​​ython機能が必要な場合はCPython APIにフォールバックすることもできます。先月か2か月、私自身もそのアイデアをいじっていました。ただし、これは非常に多くの作業であり、膨大な量のPython機能をCに変換するのは非常に困難です。 、など


2

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

あなたが探しているものがexecpのものに依存せずにCからPythonコードを実行する簡単な方法である場合。Python埋め込みAPIへの数回の呼​​び出しでラップされたPythonコードから共有ライブラリを生成できます。アプリケーションは共有ライブラリです。他の多くのライブラリ/アプリケーションで使用できるように.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にシリアル化したり、PythonからCにシリアル化したりするのが難しい場合があります。

Nuitka役立つかもしれません。

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

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