19
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PythonのC/C++拡張パターン - ポインタ

Last updated at Posted at 2016-05-13

C/C++側のポインタを Python で持っておく方法。

なにか、C++のクラスをPythonから使いたいとする。

class Hello {
 public:
  void hello();
};

PyCapsule_New

C/C++のポインタを PyObject* として返すには PyCapsule_New を使う。

static void py_hello_free(PyObject *obj);

static PyObject* py_hello_alloc(PyObject *self, PyObject *args)
{
  // Allocate a new C++ pointer h as a Python object "_Hello"
  Hello* const h= new Hello();
  
  return PyCapsule_New(h, "_Hello", py_hello_free);
}

ポインタを解放する関数を渡しておくと、Python側で解放してくれる。メモリはC/C++側で管理して解放の必要がない場合は py_hello_free のかわりに NULL を渡しておけばよい。

void py_hello_free(PyObject *obj)
{
  // Destructor function for _Hello pointer, called automatically from Python
  Hello* const h= (Hello*) PyCapsule_GetPointer(obj, "_Hello");
    
  delete h;
}

PyCapsule_GetPointer

C/C++ のポインタに戻すには PyCapsule_GetPointer

PyObject* py_hello(PyObject *self, PyObject *args)
{
  // Use _Hello pointer from Python
  PyObject* py_obj;
  
  if(!PyArg_ParseTuple(args, "O", &py_obj))
    return NULL;

  Hello* h= (Hello*) PyCapsule_GetPointer(py_obj, "_Hello");
  if(h == 0) return NULL;

  h->hello();

  Py_RETURN_NONE;
}

C/C++ の拡張を作るいつものコード

#include <cstdio>
#include "Python.h"

// ... 上のコード ...

static PyMethodDef methods[] = {
  {"hello_alloc", py_hello_alloc, METH_VARARGS, "allocate a Hello object"},
  {"hello",       py_hello,       METH_VARARGS, "call hello() method"},
  {NULL, NULL, 0, NULL}
};

static struct PyModuleDef module = {
  PyModuleDef_HEAD_INIT,
  "cext02",              // name of this module
  "Use C/C++ pointer",  // Doc String
  -1,
  methods
};

PyMODINIT_FUNC
PyInit_cext02(void) {  
  return PyModule_Create(&module);
}

いつもの setup.py

from distutils.core import setup, Extension

setup(name='cext02',
      version='0.0.1',
      description='c_ext02 pointer',
      author='Jun Koda',
      url='https://github.com/junkoda/python_c_ext',
      ext_modules=[
          Extension('cext02', ['cext02.cpp'])
      ]
)

コンパイル

$ python3 setup.py build_ext --inplace

Python から

import cext02  # Cによる拡張
h = cext02.hello_alloc() # h = new Hello() みたいなこと
cext02.hello(h) # h->hello() を呼ぶ

のように使う。(もちろん、Python の class でラッピングすれば、オブジェクトっぽく使える。)

参考

19
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?