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("%gn", 3.14)
Traceback (most recent call last):
File <stdin>, line 3, in <module>
dll.printf("%gn", 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("%gn", 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_p
print dll.getcwd() # 現在の作業ディレクトリ
dll.sqrt.restype = ctypes.c_double
dll.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.H
2.S
3.P
はい
1. PHP
ですね
PHP Go
世の中
見渡せば
Pythonばかり
PHPに日の目を
はい
PHP in Python
プロジェクト始動
http://bitbucket.org/moriyoshi/php-in-python