Perl, Python間のやり取り
やはりpyperlと同じになってきた。。。。
python,perlをいろいろ触ってて少しずつ見えてきたのでメモ程度に書いておく。
Perl->Pythonの変換
基本的な型変換はこんな感じ。
SV->PyObjectへ
if(SvPOK(sv)){ //string STRLEN len; char *s = SvPV(sv, len); o = Py_BuildValue("s#", s, len); }else if(SvNOK(sv)){ //double o = Py_BuildValue("d", SvNV(sv)); }else if(SvIOK(sv)){ //long o = Py_BuildValue("l", SvIV(sv)); }else if(SvROK(sv)){ // ref o = newSvRV_Object(self, sv); }else{ //other o = Py_BuildValue(""); }
longは怪しいけど。
SvROKのケースで具体的に何か判断し、それに対応したObjectを生成しようか迷うところ。
Python->Perlの変換
PyObject->SVへ
if (o == Py_None) { return newSV(0); }else if (PyString_Check(o)) { return newSVpvn(PyString_AS_STRING(o), PyString_GET_SIZE(o)); }else if (PyInt_Check(o)) { return newSViv(PyInt_AsLong(o)); }else if (PyLong_Check(o)) { unsigned long tmp = PyLong_AsUnsignedLong(o); return newSVuv(tmp); }else if (PyFloat_Check(o)) { return newSVnv(PyFloat_AsDouble(o)); }else if (PySvRV_Check(o)){ return PySvRV_AsSV(o); }else { return newSV(0); } return NULL;
まあマクロとかあるけど雰囲気で。
PySvRVはSVROKの時のsvのラッパーでその時のsvを返す。
refの中身
多くの場合はこれぐらいのケースの考慮でよいかな。
- 配列
- ハッシュ
- オブジェクト(?)
配列の場合はPythonObjectのtp_as_sequence,ハッシュの場合はtp_as_mapping,
オブジェクトの時はtp_getattrを実装。
そこからメソッドを呼んだりできるように実装すればいいと思う。
配列かの判断
SV *sv;
...
if (SvTYPE(SvRV(sv)) == SVt_PVAV) {
...
}
ハッシュかの判断
SV *sv;
...
if (SvTYPE(SvRV(sv)) == SVt_PVHV) {
...
}
オブジェクトの判断
SV *sv;
...
if (SvOBJECT(SvRV(sv))){
...
}
型判断をまとめて書くなら
SV *sv; SV *rv = SvRV(sv); switch (SvTYPE(rv)) { case SVt_IV: .... break; case SVt_NV: .... break; case SVt_PV: .... break; case SVt_RV: .... break; case SVt_PVAV: .... break; case SVt_PVHV: .... break; case SVt_PVCV: .... break; case SVt_PVGV: .... break; case SVt_PVMG: .... break; default: .... break; }
Perlの型名の取得
実際のperlの型名を取る
SV *sv;
PyObject *name;
...
char *ptype = sv_reftype(SvRV(sv));
name = PyString_FromString(ptype);
Perlのクラス名の取得
Perlのクラス名を取得する。
これでダメなケースってあるのかわからないけど多くはこれでいけると思う。
SV *sv; PyObject *name; ... SV *rv = SvRV(sv); if (SvOBJECT(sv)) { char *klass = HvNAME(SvSTASH(sv)); name = PyString_FromString(klass); }
blessしちゃう
ほぼ使わないであろうが...
SV *sv; ... char *klass = PyString_AsString(val); sv_bless(sv, gv_stashpv(klass, 1));
Cからしか生成しないPyObject
僕は今までぬるいpythonプログラマだったのでモジュールのinitで
- PyType_Readyして
- PyModule_AddObjectしておく
でやる方法しか知らなかった。
例えばperlのrefのsvのラッパーなんかを作りたい場合にはこうする。
PyObject * newSvRV_Object(Perl_Object *obj, SV *sv) { PySvRV_Object *self; PerlInterpreter *my_perl; my_perl = obj->perl; PERL_SET_CONTEXT(my_perl); self = PyObject_NEW(PySvRV_Object, &PySvRV_Type); if (self == NULL) return NULL; self->sv = SvREFCNT_inc(sv); self->interp = obj; Py_INCREF(self->interp); return (PyObject *)self; } static void svrv_dealloc(PySvRV_Object *self) { PerlInterpreter *my_perl; my_perl = self->interp->perl; PERL_SET_CONTEXT(my_perl); SvREFCNT_dec(self->sv); PyObject_DEL(self); Py_DECREF(self->interp); } PyTypeObject PySvRV_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "ref", /* tp_name */ sizeof(PySvRV_Object), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)svrv_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0,, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ };
svを保持したいだけなのでそのままsvを渡してPyObjectを生成する。
(わざわざsv->PyObjectに変換しtp_initにあたる関数を呼ぶとかやらなくてよい)
PyObject_NEW(マクロ)を使うと直接オブジェクトを確保できる。
PyObject_NEWで確保したPyObjectはPyObject_DELで解放しないといけない。
よくある
Py_TYPE(self)->tp_free(self);
で解放することはできない。
(ずっとはまっていた)
まあperlとのやり取りは難しいというかどう変換するか悩ましいよね。