web-dev-qa-db-ja.com

CコードからPython code?

いくつかの新しい機能を使用して大規模なCプロジェクトを拡張したいのですが、実際にはPythonで記述したいと思います。基本的に、CコードからPythonコードを呼び出します。ただし、SWIGのようなPython-> Cラッパーは、Cモジュールを作成してPythonからCを呼び出すOPPOSITEを許可します。

私はIPCまたはRPC(複数のプロセスを持つことを気にしない));つまり、純粋なPythonコンポーネントを別のプロセスで(同じマシンで)実行するアプローチを検討していますソケット(またはUNIXパイプ)からの書き込み/読み取りによってCプロジェクトと通信するようにします。my pythonコンポーネントは通信するためにソケットに読み書きできます。それは合理的なアプローチですか?特別なRPCメカニズムのようなものですか?

これまでの回答に感謝します-ただし、Cプログラムとは別のプロセスでPythonプログラムを使用したいので、IPCベースのアプローチに焦点を当てたいと思います。 Pythonインタープリター。ありがとう!を埋め込みたくありません。

38
pgb

ここに詳述されているアプローチ をお勧めします。まずPythonコードの文字列を実行する方法を説明し、そこからPython環境をセットアップしてCプログラムと対話し、Pythonを呼び出します。 Cコードからの関数、CコードからのPythonオブジェクトの操作など。

編集:本当にIPCのルートに行きたい場合は、 構造体モジュール 以上、または protlib を使用します。 PythonプロセスとCプロセスの間のほとんどの通信は、構造体を前後にやり取りすることを中心に、 ソケット経由 または 共有メモリ を介して行われます。

コマンドとその引数を表すフィールドとコードでCommand構造体を作成することをお勧めします。あなたが何を達成したいのかを知ることなく、これ以上具体的なアドバイスをすることはできませんが、一般的には protlib ライブラリをお勧めします。CとPythonプログラム(免責事項:私はprotlibの著者です)。

12
Eli Courtwright

マニュアルの関連する章を参照してください: http://docs.python.org/extending/

基本的に、pythonインタープリターをプログラムに組み込む必要があります。

5
janneb

pythonアプリケーションをシェルスクリプトでラップし、Cアプリケーションでwithを呼び出すことを検討したことがありますか?

最もエレガントなソリューションではありませんが、非常に簡単です。

4
hhafez

Python <-> C通信にIPCアプローチを使用していませんが、かなりうまくいくはずです。Cプログラムに標準のfork-execを実行させ、リダイレクトされたstdinおよびstdoutは、通信用の子プロセスにあります。素敵なテキストベースの通信により、Pythonプログラムの開発とテストが非常に簡単になります。

1
D.Shawley

IPCを使用することに決めた場合は、おそらく XML-RPC -クロスプラットフォームで散財し、簡単にPythonサーバープロジェクトを必要に応じて後で別のノードに、多くの優れた実装があります(CおよびPython ones、および here を含む、多くの here を参照) Python標準ライブラリ-他のアプローチほどスケーラブルではありませんが、ユースケースに適していると思われます)の一部である単純なXML-RPCサーバー。

それは完璧なIPCすべての場合(または、完璧なRPCでさえも!)のアプローチではないかもしれません!)私の意見では、軽微な欠陥があります。

1
Alex Martelli

別のアプリケーションでのPythonの埋め込み の「標準」アプローチを使用しました。しかし、それは複雑/退屈です。 Pythonの各新しい関数は実装するのが苦痛です。

CからPyPyを呼び出す の例を見ました。インターフェイスを簡素化するためにCFFIを使用しますが、PythonではなくPyPyが必要です。少なくとも高レベルで、最初にこの例を読んで理解してください。

Pythonで動作するようにC/PyPyの例を変更しました。 CFFIを使用してCからPythonを呼び出す方法は次のとおりです。

私の例は、1つではなくPythonで3つの関数を実装したため、より複雑です。データをやり取りする追加の側面をカバーしたかった。

複雑な部分は、apiのアドレスをPythonに渡すことに分離されました。それは一度だけ実装する必要があります。その後、Pythonで新しい関数を簡単に追加できます。

interface.h

// These are the three functions that I implemented in Python.
// Any additional function would be added here.
struct API {
    double (*add_numbers)(double x, double y);
    char* (*dump_buffer)(char *buffer, int buffer_size);
    int (*release_object)(char *obj);
};

test_cffi.c

//
// Calling Python from C.
// Based on Calling PyPy from C:
// http://doc.pypy.org/en/latest/embedding.html#more-complete-example
//

#include <stdio.h>
#include <assert.h>

#include "Python.h"

#include "interface.h"

struct API api;   /* global var */

int main(int argc, char *argv[])
{
    int rc;

    // Start Python interpreter and initialize "api" in interface.py using 
    // old style "Embedding Python in Another Application":
    // https://docs.python.org/2/extending/embedding.html#embedding-python-in-another-application
    PyObject *pName, *pModule, *py_results;
    PyObject *fill_api;
#define PYVERIFY(exp) if ((exp) == 0) { fprintf(stderr, "%s[%d]: ", __FILE__, __LINE__); PyErr_Print(); exit(1); }

    Py_SetProgramName(argv[0]);  /* optional but recommended */
    Py_Initialize();
    PyRun_SimpleString(
            "import sys;"
            "sys.path.insert(0, '.')" );

    PYVERIFY( pName = PyString_FromString("interface") )
    PYVERIFY( pModule = PyImport_Import(pName) )
    Py_DECREF(pName);
    PYVERIFY( fill_api = PyObject_GetAttrString(pModule, "fill_api") )

    // "k" = [unsigned long],
    // see https://docs.python.org/2/c-api/arg.html#c.Py_BuildValue
    PYVERIFY( py_results = PyObject_CallFunction(fill_api, "k", &api) )
    assert(py_results == Py_None);

    // Call Python function from C using cffi.
    printf("sum: %f\n", api.add_numbers(12.3, 45.6));

    // More complex example.
    char buffer[20];
    char * result = api.dump_buffer(buffer, sizeof buffer);
    assert(result != 0);
    printf("buffer: %s\n", result);

    // Let Python perform garbage collection on result now.
    rc = api.release_object(result);
    assert(rc == 0);

    // Close Python interpreter.
    Py_Finalize();

    return 0;
}

interface.py

import cffi
import sys
import traceback

ffi = cffi.FFI()
ffi.cdef(file('interface.h').read())

# Hold references to objects to prevent garbage collection.
noGCDict = {}

# Add two numbers.
# This function was copied from the PyPy example.
@ffi.callback("double (double, double)")
def add_numbers(x, y):
    return x + y

# Convert input buffer to repr(buffer).
@ffi.callback("char *(char*, int)")
def dump_buffer(buffer, buffer_len):
    try:
        # First attempt to access data in buffer.
        # Using the ffi/lib objects:
        # http://cffi.readthedocs.org/en/latest/using.html#using-the-ffi-lib-objects
        # One char at time, Looks inefficient.
        #data = ''.join([buffer[i] for i in xrange(buffer_len)])

        # Second attempt.
        # FFI Interface:
        # http://cffi.readthedocs.org/en/latest/using.html#ffi-interface
        # Works but doc says "str() gives inconsistent results".
        #data = str( ffi.buffer(buffer, buffer_len) )

        # Convert C buffer to Python str.
        # Doc says [:] is recommended instead of str().
        data = ffi.buffer(buffer, buffer_len)[:]

        # The goal is to return repr(data)
        # but it has to be converted to a C buffer.
        result = ffi.new('char []', repr(data))

        # Save reference to data so it's not freed until released by C program.
        noGCDict[ffi.addressof(result)] = result

        return result
    except:
        print >>sys.stderr, traceback.format_exc()
        return ffi.NULL

# Release object so that Python can reclaim the memory.
@ffi.callback("int (char*)")
def release_object(ptr):
    try:
        del noGCDict[ptr]
        return 0
    except:
        print >>sys.stderr, traceback.format_exc()
        return 1

def fill_api(ptr):
    global api
    api = ffi.cast("struct API*", ptr)

    api.add_numbers = add_numbers
    api.dump_buffer = dump_buffer
    api.release_object = release_object

コンパイル:

gcc -o test_cffi test_cffi.c -I/home/jmudd/pgsql-native/Python-2.7.10.install/include/python2.7 -L/home/jmudd/pgsql-native/Python-2.7.10.install/lib -lpython2.7

実行:

$ test_cffi
sum: 57.900000
buffer: 'T\x9e\x04\x08\xa8\x93\xff\xbf]\x86\x04\x08\x00\x00\x00\x00\x00\x00\x00\x00'
$ 
0
JohnMudd

どうやらPython win32 dllにコンパイルできる必要があり、問題を解決します

C#コードをwin32 dllに変換することにより、あらゆる開発ツールで使用できるようになります。

0
Mandrake

これは非常にいいようです http://thrift.Apache.org/ 、それについての本さえあります。

詳細:

Apache Thriftソフトウェアフレームワークは、スケーラブルな言語間サービス開発のために、ソフトウェアスタックとコード生成エンジンを組み合わせて、C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#の間で効率的かつシームレスに動作するサービスを構築します。 Cocoa、JavaScript、Node.js、Smalltalk、OCaml、Delphi、およびその他の言語。

0
jhegedus