Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

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で

  1. PyType_Readyして
  2. 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とのやり取りは難しいというかどう変換するか悩ましいよね。