web-dev-qa-db-ja.com

ctypes-初心者

私は、ACライブラリをpythonクラスに「ラップ」するタスクを持っています。ドキュメントは、この問題について非常にあいまいです。彼らは、高度なpythonユーザーctypesを実装します。私はpythonの初心者であり、助けが必要です。

段階的なヘルプがあれば素晴らしいでしょう。

だから私は私のcライブラリを持っています。私は何をしますか?どのファイルをどこに置きますか?ライブラリをインポートするにはどうすればよいですか? Pythonに「自動ラップ」する方法があるかもしれないと読みましたか?

(ちなみに、私はpython.netでctypesチュートリアルを実行しましたが、機能しません。意味残りのステップを埋めることができると想定していると考えています。

実際、これは私が彼らのコードで得たエラーです:

File "importtest.py", line 1
   >>> from ctypes import *
   SyntaxError: invalid syntax

これについては、ステップバイステップのヘルプを実際に使用できます。ありがとう〜

83
spentak

簡単で汚いctypesチュートリアルを次に示します。

まず、Cライブラリを作成します。 Hello worldの簡単な例を次に示します。

testlib.c

_#include <stdio.h>

void myprint(void);

void myprint()
{
    printf("hello world\n");
}
_

次に、共有ライブラリとしてコンパイルします( mac fix found here ):

_$ gcc -shared -Wl,-soname,testlib -o testlib.so -fPIC testlib.c

# or... for Mac OS X 
$ gcc -shared -Wl,-install_name,testlib.so -o testlib.so -fPIC testlib.c
_

次に、ctypesを使用してラッパーを作成します。

testlibwrapper.py

_import ctypes

testlib = ctypes.CDLL('/full/path/to/testlib.so')
testlib.myprint()
_

それを実行してください:

_$ python testlibwrapper.py
_

そして、出力が表示されるはずです

_Hello world
$
_

すでにライブラリを念頭に置いている場合は、チュートリアルのPython以外の部分をスキップできます。 ctypesが_/usr/lib_または別の標準ディレクトリに配置してライブラリを見つけることができることを確認してください。これを行う場合、ラッパーの作成時にフルパスを指定する必要はありません。これを行わない場合は、ctypes.CDLL()を呼び出すときにライブラリのフルパスを指定する必要があります。

これは、より包括的なチュートリアルの場所ではありませんが、このサイトで特定の問題について助けを求める場合、コミュニティがあなたを助けると確信しています。

PS:ctypes.CDLL('libc.so.6')を使用したため、Linuxを使用していると想定しています。別のOSを使用している場合、状況は少し(またはかなり)変化する可能性があります。

201
Chinmay Kanchi

Chinmay Kanchiによる答えは素晴らしいですが、変数/配列をC++コードに渡したり返す関数の例が必要でした。他の人に役立つ場合に備えて、ここに含めます。

整数を渡して返す

整数を受け取り、戻り値に1を加算する関数のC++コード。

extern "C" int add_one(int i)
{
    return i+1;
}

ファイルtest.cppとして保存します。 必須 extern "C"に注意してください(Cコードの場合は削除できます)。これはg ++を使用してコンパイルされており、引数はChinmay Kanchiの回答に似ていますが、

g++ -shared -o testlib.so -fPIC test.cpp

Pythonコードは、Pythonスクリプトと同じディレクトリにある共有ライブラリへのパスを想定して、load_librarynumpy.ctypeslibを使用します。

import numpy.ctypeslib as ctl
import ctypes

libname = 'testlib.so'
libdir = './'
lib=ctl.load_library(libname, libdir)

py_add_one = lib.add_one
py_add_one.argtypes = [ctypes.c_int]
value = 5
results = py_add_one(value)
print(results)

期待どおり6が出力されます。

配列の受け渡しと印刷

次のように配列を渡すこともできます。Cコードで配列の要素を出力するには、

extern "C" void print_array(double* array, int N)
{
    for (int i=0; i<N; i++) 
        cout << i << " " << array[i] << endl;
}

以前のようにコンパイルされ、同じ方法でインポートされます。この関数を使用するための追加のPythonコードは、

py_print_array = lib.print_array
py_print_array.argtypes = [ctl.ndpointer(np.float64, 
                                         flags='aligned, c_contiguous'), 
                           ctypes.c_int]
A = np.array([1.4,2.6,3.0], dtype=np.float64)
py_print_array(A, 3)

ここで、配列を指定します。print_arrayの最初の引数は、整列されたc_contiguous 64ビットfloatのNumpy配列へのポインタとして、2番目の引数はCコードにNumpy配列の要素数を伝える整数として。これは、Cコードによって次のように出力されます。

1.4
2.6
3.0
38
Ed Smith

まず、pythonの例で見られる>>>コードは、Pythonコードであることを示す方法です。 Pythonコードを出力から分離するために使用されます。このような:

>>> 4+5
9

ここで、>>>で始まる行がPythonコードであり、9が結果となることがわかります。これは、Pythonインタープリターを開始した場合の外観ですなぜそれがそうなのか。

>>>部分を.pyファイルに入力することはありません。

これで構文エラーが処理されます。

第二に、ctypesはPythonライブラリをラップするいくつかの方法の1つにすぎません。他の方法は [〜#〜] swig [〜#〜] です。これはPythonライブラリを見て、C APIを公開するPython C拡張モジュールを生成します。別の方法は Cython を使用することです。

それらにはすべて利点と欠点があります。

SWIGはC APIのみをPythonに公開します。つまり、オブジェクトなど何も取得しないので、それを行う別のPythonファイルを作成する必要があります。ただし、「wowza」と呼ばれるモジュールと、C APIのラッパーである「_wowza」と呼ばれるSWIGモジュールを持つことは一般的です。これは素晴らしく簡単な方法です。

CythonはC-Extensionファイルを生成します。作成するすべてのPythonコードがCで作成されるという利点があるため、作成するオブジェクトもCで作成されるため、パフォーマンスが向上する可能性があります。ただし、Cとのインターフェイス方法を学習する必要があるため、使用方法を学習するには少し余分な作業が必要です。

ctypesには、コンパイルするCコードがないという利点があるため、他の誰かが作成した標準ライブラリのラッピングに使用すると非常に便利であり、WindowsおよびOS Xのバイナリバージョンには既に存在します。

11
Lennart Regebro