рдкрд╛рдпрдерди рд╕реЗ C / C ++ (C API)

рдореБрдЦреНрдп

рд╣рдо рдкрд╛рдпрдерди 3 рд╕реЗ C / C ++ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЗ рд╡рд┐рд╖рдп рдХреЛ рдЬрд╛рд░реА рд░рдЦрддреЗ рд╣реИрдВ ред рдЕрдм рд╣рдо рдореЙрдбреНрдпреВрд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реА рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рд╣рдо рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╕рд┐рдлреА рдФрд░ рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣рдорд╛рд░реЗ рдЬреАрд╡рди рдХреЛ рдХреИрд╕реЗ рд╕рд░рд▓ рдмрдирд╛рддреЗ рд╣реИрдВред рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░реА рд░рд╛рдп рдореЗрдВ рдпрд╣ рд╕рдмрд╕реЗ рдХрдард┐рди рддрд░реАрдХрд╛ рд╣реИред


рд╕реА


рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рддрд░реНрдХреЛрдВ рдХреЗ рд╕рд╛рде рд╡реИрд╢реНрд╡рд┐рдХ рдЪрд░, рд╕рдВрд░рдЪрдирд╛рдУрдВ рдФрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд░реАрдХреНрд╖рдг рдкреБрд╕реНрддрдХрд╛рд▓рдпред рдЕрдкрдиреЗ рд▓реЗрдЦреЛрдВ рдореЗрдВ рдореИрдВ рдЙрд╕реА рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдмрджрд▓рд╛рд╡реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ, рдЬреЛ рдЕрдм рдореЗрд░реЗ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рд╡рд┐рдзрд┐ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИред рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдкрд┐рдЫрд▓реЗ рддрд░реАрдХреЛрдВ рдХреЗ рд▓рд┐рдВрдХред
test.h


typedef struct test_st_s test_st_t; extern int a; extern double b; extern char c; static PyObject *func_hello(PyObject *self, PyObject *args); static PyObject *func_ret_int(PyObject *self, PyObject *args); static PyObject *func_ret_double(PyObject *self, PyObject *args); static PyObject *func_ret_str(PyObject *self, PyObject *args); static PyObject *func_many_args(PyObject *self, PyObject *args); static PyObject *func_ret_struct(PyObject *self, PyObject *args); struct test_st_s { PyObject_HEAD //    ,    int val1; double val2; char val3; }; 

test.c


 //    static PyMethodDef methods[] = { {"func_hello", func_hello, METH_NOARGS, "func_hello"}, //    {"func_ret_int", func_ret_int, METH_VARARGS, "func_ret_int"}, //    {"func_ret_double", func_ret_double, METH_VARARGS, "func_ret_double"}, {"func_ret_str", func_ret_str, METH_VARARGS, "func_ret_str"}, {"func_many_args", func_many_args, METH_VARARGS, "func_many_args"}, {"func_ret_struct", func_ret_struct, METH_VARARGS, "func_ret_struct"}, {NULL, NULL, 0, NULL} }; //   static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "_test", "Test module", -1, methods }; //   PyMODINIT_FUNC PyInit__test(void) { PyObject *mod = PyModule_Create(&module); //    PyModule_AddObject(mod, "a", PyLong_FromLong(a)); // int PyModule_AddObject(mod, "b", PyFloat_FromDouble(b)); // double PyModule_AddObject(mod, "c", Py_BuildValue("b", c)); // char //   //    if (PyType_Ready(&test_st_t_Type) < 0) return NULL; Py_INCREF(&test_st_t_Type); PyModule_AddObject(mod, "test_st_t", (PyObject *) &test_st_t_Type); return mod; } /** *  ,  . */ int a = 5; double b = 5.12345; char c = 'X'; // 88 static PyObject * func_hello(PyObject *self, PyObject *args) { //   args,   warning  . puts("Hello!"); Py_RETURN_NONE; } /** *       int   . */ static PyObject * func_ret_int(PyObject *self, PyObject *args) { int val; //  -  if (PyTuple_Size(args) != 1) { PyErr_SetString(self, "func_ret_int args error"); } PyArg_ParseTuple(args, "i", &val); /* *  . * //   PyObject *obj = PyTuple_GetItem(args, 0); //     int/long if (PyLong_Check(obj)) { PyErr_Print(); } //  (PyObject *)  int val = _PyLong_AsInt(obj); */ printf("C get func_ret_int: %d\n", val); return Py_BuildValue("i", val); } /** *       double   . */ static PyObject * func_ret_double(PyObject *self, PyObject *args) { double val; if (PyTuple_Size(args) != 1) { PyErr_SetString(self, "func_ret_double args error"); } PyArg_ParseTuple(args, "d", &val); printf("C get func_ret_double: %f\n", val); return Py_BuildValue("f", val); } /** *  string   . */ static PyObject * func_ret_str(PyObject *self, PyObject *args) { char *val; if (PyTuple_Size(args) != 1) { PyErr_SetString(self, "func_ret_str args error"); } PyArg_ParseTuple(args, "s", &val); /* *  . * PyObject *obj = PyTuple_GetItem(args, 0); PyObject* pResultRepr = PyObject_Repr(obj); val = PyBytes_AS_STRING(PyUnicode_AsEncodedString(pResultRepr, "utf-8", "ERROR")); */ printf("C get func_ret_str: %s\n", val); return Py_BuildValue("s", val); } /** *       int, double, char *. */ static PyObject * func_many_args(PyObject *self, PyObject *args) { int val1; double val2; char *val3; if (PyTuple_Size(args) != 3) { PyErr_SetString(self, "func_ret_str args error"); } PyArg_ParseTuple(args, "ids", &val1, &val2, &val3); printf("C get func_many_args: int - %d, double - %f, string - %s\n", val1, val2, val3); return Py_BuildValue("ifs", val1, val2, val3); } static PyObject * func_ret_struct(PyObject *self, PyObject *args) { test_st_t *st; //    Python if (!PyArg_ParseTuple(args, "O", &st)) // O -   Py_RETURN_NONE; printf("C get test_st: val1 - %d, val2 - %f, val3 - %d\n", st->val1++, st->val2++, st->val3++); return Py_BuildValue("O", st); } 

рдореЙрдбреНрдпреВрд▓ рдХреЛ рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рдЗрд╕рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛрдЧрд╛: рдлрд╝рдВрдХреНрд╢рди, рд╡реИрд╢реНрд╡рд┐рдХ рдЪрд░ рдФрд░ рд╕рдВрд░рдЪрдирд╛рдПрдВред рдкреНрд░рддреНрдпреЗрдХ рдРрд╕реА рдЪреАрдЬрд╝ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬреЛ рдЙрд╕рдХреЗ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ (рд╕рдВрд░рдЪрдирд╛ ...) рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдХрдард┐рди рдЪреАрдЬрд╝ рд╣реИред рд▓рдЧрднрдЧ рдРрд╕реА рдлрд╝рд╛рдЗрд▓ cffi рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдИ рдЧрдИ рд╣реИред


рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд╢реАрд░реНрд╖ рд▓реЗрдЦ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдХрдиреЗрдХреНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛:


 #include <Python.h> #include <structmember.h> //     

рд╕рдВрдХрд▓рди рдЭрдВрдбреЗ:


 $(python3-config --includes --ldflags) -fPIC 

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рдХреНрд░рд┐рдпрд╛ рддрд░реНрдХреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ:


 PyArg_ParseTuple(args, "ids", &val1, &val2, &val3); 

рдкрд╣рд▓рд╛ рдкреНрд░рдХрд╛рд░ int рдХрд╛ рдПрдХ рддрд░реНрдХ рд╣реИ, рдЗрд╕рдореЗрдВ рдЕрдХреНрд╖рд░ рдкрджрдирд╛рдо i рд╣реИ
2 рдлреНрд▓реЛрдЯ / рдбрдмрд▓ - рдбреА
рддреАрд╕рд░рд╛ рддрд╛рд░ - s
рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд╕рднреА рд╕рдВрднрд╛рд╡рд┐рдд рдкрддреНрд░ рдкрджрдирд╛рдо рдпрд╣рд╛рдВ рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред


рдЕрдм рд╣рдо рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рд╡рд░реНрдгрди рдХреИрд╕реЗ рдХрд░реЗрдВред
struct.c:


 //   static void test_st_t_dealloc(test_st_t* self) { Py_TYPE(self)->tp_free((PyObject*)self); } //   static PyObject * test_st_t_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { test_st_t *self; self = (test_st_t *)type->tp_alloc(type, 0); if (self != NULL) { self->val1 = 0; self->val2 = 0.0; self->val3 = 0; } return (PyObject *)self; } //  ,     static int test_st_t_init(test_st_t *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"val1", "val2", "val3", NULL}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "|idb", kwlist, &self->val1, &self->val2, &self->val3)) return -1; return 0; } //       static PyMemberDef test_st_t_members[] = { {"val1", T_INT, offsetof(test_st_t, val1), 0, "int"}, {"val2", T_DOUBLE, offsetof(test_st_t, val2), 0, "double"}, {"val3", T_CHAR, offsetof(test_st_t, val3), 0, "char"}, {NULL} }; //  ,    static PyObject* test_st_print(PyObject *self, PyObject *args) { test_st_t *st; //    Python if (!PyArg_ParseTuple(args, "O", &st)) // O -   Py_RETURN_NONE; printf("method: val1 - %d, val2 - %f, val3 - %d\n", st->val1++, st->val2++, st->val3++); Py_RETURN_NONE; } //   ,        ! //   ! static PyMethodDef test_st_t_methods[] = { {"print", test_st_print, METH_VARARGS, "doc string"}, {NULL} /* Sentinel */ }; //    .  , , ,   ..  .. PyTypeObject test_st_t_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_test.test_st_t", /* tp_name */ sizeof(test_st_t), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor) test_st_t_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ "test_st_t objects", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ test_st_t_methods, /* tp_methods */ test_st_t_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc) test_st_t_init, /* tp_init */ 0, /* tp_alloc */ test_st_t_new, /* tp_new */ }; 

рдФрд░ рд╡рд╣ рд╕рдм рдХреЗ рд▓рд┐рдП рд╣реИ:


 struct test_st_s { PyObject_HEAD //    ,    int val1; double val2; char val3; }; 

рд╕рд╣рдордд рд╣реВрдВ, рдереЛрдбрд╝рд╛ рдирд╣реАрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рддрд░реАрдХреЛрдВ рдХреЛ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рд▓рд┐рдП рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, test_st_print )ред
рдХреЛрдб рдореЗрдВ, рдореИрдВ рдЕрд▓рдЧ рд╕реЗ рдХрдо рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдВ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реВрдВред


рдЕрдЬрдЧрд░


рдкрд╛рдпрдерди рд╕реЗ рд╕реА рдореЙрдбреНрдпреВрд▓ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг:


 import sys import time #    _test sys.path.append('.') sys.path.append('lib/') sys.path.append('../../lib/') import _test ### ## C ### print("C API\n") print("C\n") start_time = time.time() ## #    ## print('  :') print('ret func_hello: ', _test.func_hello()) print('ret func_ret_int: ', _test.func_ret_int(101)) print('ret func_ret_double: ', _test.func_ret_double(12.123456789)) print('ret func_ret_str: ', _test.func_ret_str('Hello!')) print('ret func_many_args: ', _test.func_many_args(15, 18.1617, "Many arguments!")) ## #    ## print('\n  :') print('ret a: ', _test.a) #   . _test.a = 22 print('new a: ', _test.a) print('ret b: ', _test.b) print('ret c: ', _test.c) ## #    ## print('\n  :') #   st = _test.test_st_t(1, 2.3456789, 88) print('st.val1 = {}\nst.val2 = {}\nst.val3 = {}'.format(st.val1, st.val2, st.val3)) st = _test.func_ret_struct(st) print("ret func_ret_struct:") print('st.val1 = {}\nst.val2 = {}\nst.val3 = {}'.format(st.val1, st.val2, st.val3)) #   print  ,    C   #           st.print(st) #   print("--- {} seconds ---".format((time.time() - start_time))) 

рдореЙрдбреНрдпреВрд▓ рджреЗрд╢реА рд╣реЛ рдЧрдпрд╛ рд╣реИред


рд╕реА рдПрдкреАрдЖрдИ рдХреЗ рдкреЗрд╢реЗрд╡рд░реЛрдВ рдФрд░ рд╡рд┐рдкрдХреНрд╖


рдкреЗрд╢реЗрд╡рд░реЛрдВ :


  • рдЕрдЬрдЧрд░ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╕рд╛рди рд╣реИ

рд╡рд┐рдкрдХреНрд╖ :


  • C API рдореЗрдВ рдЖрдкрдХреЗ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ
  • рд╢реБрджреНрдз рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЗ рд▓рд┐рдП рдЕрдЬрдЧрд░ рдХреЗ рд▓рд┐рдП рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдХрдард┐рди рд╣реИ, рдФрд░ рдЙрдирдХреЗ рд▓рд┐рдП рднреА рдирд╣реАрдВ ... (рдореЗрд░реЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рд╕рд░рд▓ cypyps рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣реИ)
  • рдореЙрдбреНрдпреВрд▓ (рдкреБрд╕реНрддрдХрд╛рд▓рдп) рдХреЗрд╡рд▓ рдкрд╛рдпрдерди рдХреЗ рд▓рд┐рдП рд╣реЛрдЧрд╛

1000 рдХреЗ рд╕рд╛рде рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рдзрд┐ рдкрд░ рдФрд╕рдд рдкрд░реАрдХреНрд╖рдг рдирд┐рд╖реНрдкрд╛рджрди рд╕рдордп:


  • ctypes: - 0.0004987692832946777 рд╕реЗрдХрдВрдб ---
  • CFFI: - 0.00038521790504455566 рд╕реЗрдХрдВрдб ---
  • pybind: - 0.0004547207355499268 рд╕реЗрдХрдВрдб ---
  • C API: - 0.0003561973571777344 рд╕реЗрдХрдВрдб ---

рд╕рдВрджрд░реНрдн


Source: https://habr.com/ru/post/hi469043/


All Articles