ctypes拡張モジュール

Preview:

DESCRIPTION

 

Citation preview

ctype拡張モジュールMoriyoshi Koizumi <mozo@mozo.jp>

自己紹介● はてな:moriyoshi● twitter:moriyoshit● 某研究機関で生物シミュレーションの研究をし

ています。● 日々PythonとC++を書いてます!!● 好きなテンプレート言語はPHPです!!!!

パーフェクトPHP出ました

月刊Python出ます

BeepLoudやってます!

はい

ctypes拡張モジュールとは● Python 2.5より追加● Thomas Heller作● C言語で書かれた共有ライブラリをPythonから

利用するためのライブラリ● 中身はlibffiのラッパー● 複数のOSに対応● といってもピンときませんよね...

C言語で書かれた共有ライブラリをPythonから利用するための

ライブラリ

それCythonでできるよ● CythonはCython拡張を施されたPythonで書か

れたコードをCに変換する仕組み● 生成されたCのコードをPythonのC拡張にコン

パイルしない限りは利用できない● 開発にはCをコンパイル、リンクする環境が必

要● 配布時にも、各プラットフォーム用のバイナリ

の準備が必要

ctypesなら?● 純粋なPythonスクリプトからCの関数を呼び出

せる– コンパイル不要– 配布時のバイナリ同梱も不要

● プロトタイプ作成、C関数のテストコード作成に威力を発揮

Show me what it looks like!

import ctypes

# 標準Cライブラリを読み込むdll = ctypes.CDLL("/usr/lib/libSystem.B.dylib")

# ライブラリの関数を呼び出すdll.printf("Hello, %s world!\n", "bucho")

基本的な使い方● ctypes.CDLL オブジェクトを、引数として共有

ライブラリ名を渡して生成● ctypesオブジェクトの属性にアクセスすると、

C関数を呼び出すためのラッパー関数が自動的に生成される

● ラッパー関数は普通のPythonの関数として扱える

● ラッパー関数に渡す引数は自動的にCの型に変換される

デモ

値ラッパーimport ctypes

dll = ctypes.CDLL("/usr/lib/libSystem.B.dylib")

dll.printf("%g\n", 3.14)

Traceback (most recent call last): File <stdin>, line 3, in <module> dll.printf("%g\n", 3.14)ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: Don't know how to convert parameter 2

実行結果

値ラッパーimport ctypes

dll = ctypes.CDLL("/usr/lib/libSystem.B.dylib")

dll.printf("%g\n", ctypes.c_double(3.14))

3.14

実行結果

値ラッパー● 組み込みのPythonの型とCの型は一対一で対応

していない● Cの型に対応するPython型をctypes側で用意● 明示的に型を指定してC関数を呼び出したい場

合は値ラッパーのオブジェクトを渡すと、最終的に対応するCの型に変換される

値ラッパー値ラッパークラス 対応するCの型c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong

char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long

c_foat, c_double, c_longdouble

foat, double, long double

c_char_p, c_wchar_p char *, wchar_t*c_void_p void *

など

もうちょっと複雑な例import ctypes

# 標準Cライブラリを読み込むdll = ctypes.CDLL("/usr/lib/libSystem.B.dylib")

# ライブラリの関数を呼び出すdll.getcwd.restype = ctypes.c_char_pprint dll.getcwd() # 現在の作業ディレクトリ

dll.sqrt.restype = ctypes.c_doubledll.sqrt.argtypes = (ctypes.c_double, )print dll.sqrt(16) # 16の平方根

もうちょっと複雑な例● C関数の戻り値の型は、デフォルトではint型で

あるとみなされる● C関数のシグニチャを指定するときは、

ラッパー関数の以下の属性を指定する。– restype– argtypes

ポインタ渡しimport ctypes

dll = ctypes.CDLL("/usr/lib/libSystem.B.dylib")

retval = ctypes.c_int()dll.scanf("%d", ctypes.byref(retval))print retval

ポインタ渡し● 引数に指定されたポインタの示す先に戻り値を

返すようなC関数を扱う場合● ctypes.byref()

ctypes.POINTER● 任意の型のポインタ型を作る場合は

ctypes.POINTER(型) を呼ぶと、対応するポインタ型が作られる

● ctypes.POINTER(ctypes.c_int) → int *

ctypes.POINTER

import ctypes

c_int_p = ctypes.POINTER(ctypes.c_int)

dll = ctypes.CDLL("/usr/lib/libSystem.B.dylib")

retval = ctypes.c_int()dll.scanf("%d", c_int_p(retval))print retval

※このケースだと、ctypes.byref() 使った方が早いです。

構造体● ctypes.Structureクラスを継承したクラスを作る

ことで、Cの構造体に対応したラッパー型を作れる

● _fields_ 属性に (フィールド名, 型) からなるタプルのリストを渡す

構造体struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; char *tm_zone; long tm_gmtoff; };

class TMStructure(ctypes.Structure): _fields_ = [ ('tm_sec', ctypes.c_int), ('tm_min', ctypes.c_int), ('tm_hour', ctypes.c_int), ('tm_mday', ctypes.c_int), ('tm_mon', ctypes.c_int), ('tm_year', ctypes.c_int), ('tm_wday', ctypes.c_int), ('tm_yday', ctypes.c_int), ('tm_isdst', ctypes.c_int), ('tm_zone', ctypes.c_char_p), ('tm_gmtoff', ctypes.c_long)]

コールバック関数void call_callback(void(*cb)(const char *)){ cb("hoge");}

import ctypes

dll = ctypes.CDLL("libcallback.dylib")

cfun = ctypes.CFUNCTYPE(None, ctypes.c_char_p)

def callback(string): print "Hello, %s world!" % string

dll.call_callback(cfun(callback))

コールバック関数● ctypes.CFUNCTYPE(戻り値の型, [引数の型, 引

数の型...]) を呼び出して、コールバック関数のラッパーオブジェクトを生成する

● ラッパーオブジェクトは、C関数の呼び出し時に、関数ポインタに変換される

クロスプラットフォーム● MacのPythonでも● WindowsのPythonでも● Free UnixのPythonでも● それからIronPythonでも

複数プラットフォームをサポートするときの注意点

● たとえば標準C関数のライブラリ名はプラットフォームごとに違う

● sys.platform などでOSを判定して対処

まとめ● dll = ctypes.CDLL()で読み込み● dll.[関数名]() で関数を呼び出す● 関数のシグニチャを指定したい場合はrestypeと

argtypes● ラッパー型 c_*● ポインタ渡しは ctypes.byref()● 構造体は ctypes.Structure● コールバック関数は ctypes.CFUNCTYPE()

ご清聴ありがとうございました

はい

始まって

しまいました

すべらない話

PSP®Go

値下げしました

さて

P○P Go

○の中に入る文字は?

1.H2.S3.P

はい

1. PHP

ですね

PHP Go

世の中

見渡せば

Pythonばかり

PHPに日の目を

はい

PHP in Python

プロジェクト始動

http://bitbucket.org/moriyoshi/php-in-python

Recommended