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_byte, c_ubyte, c_short,
c_ushort, c_int, c_uint,
c_long, c_ulong, c_longlong,
c_ulonglong
c_foat, c_double,
c_longdouble
c_char_p, c_wchar_p
c_void_p

対応するCの型
char, unsigned char, short,
unsigned short, int,
unsigned int, long, unsigned
long, long long, unsigned
long long
foat, double, long double
char *, wchar_t*
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

Sign up to vote on this title
UsefulNot useful