qshinoの日記

Powershell関係と徒然なこと

c でpython module 作成

Cでpyton module

Cでpython module を作成する流れは下記の通り。

  1. cでソースを作成。
  2. setup.py でコンパイルし、.soを作成。
  3. python から利用。

Cソース

#define PY_SSIZE_T_CLEAN
#include <Python.h>

static PyObject * spam_system( 
  PyObject *self, 
  PyObject *args) { 

  const char *command; 
  int sts; 

  if (!PyArg_ParseTuple(args, "s", &command)) 
    return NULL; 
  sts = system(command);
  return PyLong_FromLong(sts); 
}


static PyObject* hello (
  PyObject *self, PyObject *args) { 

  printf("How are you?\n");

  Py_RETURN_NONE; 
} 

static PyObject* push(
  PyObject *self, PyObject *args){ 

  PyObject *p_list, *inthert_val, *receive_list;  
 
  if(!PyArg_ParseTuple(args, "O!i", &PyList_Type, &p_list, &inthert_val)) 
    return NULL;
  receive_list = PySequence_List(p_list);
  printf("pushing %d\n", inthert_val); 
  PyList_Append(receive_list, Py_BuildValue("i", inthert_val));

  return receive_list;
} 

static PyObject* pop (
  PyObject *self, PyObject *args){ 
  PyObject *p_list, *p_value; int size; long val; 
  if(!PyArg_ParseTuple(args, "O!", &PyList_Type, &p_list)) 
  return NULL;
  size = PyList_Size(p_list);
  p_value = PyList_GetItem(p_list, size - 1); 
  val = PyLong_AsLong(p_value);   
  printf("poping %d\n", val);
  return p_value; 
}

static PyMethodDef pmethod[] = { 
   {"spam_system", (PyCFunction) spam_system, METH_NOARGS, "primer: ststem"}, 
  {"hello", (PyCFunction) hello, METH_NOARGS, "primer: hello"}, 
  {"push", (PyCFunction) push, METH_VARARGS, "primer: push"},   
  {"pop", (PyCFunction)pop, METH_VARARGS, "primer: pop"}, 
  {NULL, NULL, 0, NULL} 
};

static struct PyModuleDef pm = { 
  PyModuleDef_HEAD_INIT,  "primer", NULL, -1, pmethod 
};

PyMODINIT_FUNC PyInit_primer (void) { 
  return PyModule_Create( &pm ); 
}

return NULLの所、大丈夫なのだろうか? python document でもNULLを返しているが、NULLとPy_RETURN_NONEの違いは? NULLはエラーらしい。例外処理に関しては、また後で。

  • note: "Python.h" は下記をインクルード:  <stdio.h> 、 <string.h> 、 <errno.h> 、 <stdlib.h> 

初期化

int main(int argc, char *argv[]) { 
  wchar_t *program = Py_DecodeLocale(argv[0], NULL); 

  if ( program == NULL ) { 
    fprintf(stderr, "Fatal error: cannot decode argv[0]\n"); 
    exit(1); 
  } 

/* Add a built-in module, before Py_Initialize */

  PyImport_AppendInittab( "primer",  PyInit_primer ); 

/* Pass argv[0] to the Python interpreter */ 

  Py_SetProgramName( program );

 /* Initialize the Python interpreter. Required. */ 

  Py_Initialize(); 

  /* Optionally import the module; alternatively, import can be deferred until the embedded script imports it. */

  PyImport_ImportModule( "primer" ); 
  ... 
  PyMem_RawFree( program ); 
  return 0; 
}

setup.py

Cソースをコンパイルするsetup.pyを作成する。

# python setup.py build_ext -i
# setup.py

from distutils.core import setup, Extension 

setup(
  name='primer', 
  version='1.0', 
  ext_modules=[
    Extension('primer', ['primer.c'])
  ] 
)

コンパイル

python setup.py build_ext -i

モジュール利用

# python usecase

import primer

primer.hello()

lista = primer.push([1, 2], 3) 
print(list) 

val = primer.pop(lista) 
print(val) 


出力

How are you?
pushing 3
[1, 2, 3] 
poping 3
3

参考

https://docs.python.org/ja/3/extending/extending.html

https://qiita.com/Kashiwara/items/2088ba011446637aa8f4