Cython - importing cython modules and merging them

2019-09-14 18:29发布

I am trying to wrap python functions to C++ apis using Cython. I have 2 modules sam1.pyx and sam2.pyx

## - sam1.pyx
import sam2
cdef public double calc(double x, double y):
  return sam2.calc_sub(x,y)

the contents of the file sam2.py is as follows

## - sam2.py
def calc_sub(x, y):
  return x*y

with such a structure, the wrapped sam1.h along with the corresponding sam1.so are generated

During the usage in Cpp application,

#include<iostream>
#include<Python.h>
#include"sam1.h"

using namespace std;

int main(){

  Py_Initialize();

  #if PY_MAJOR_VERSION < 3
   initsam1();
  #else
   PyInit_sam1();
  #endif  

  cout << "Starting Program!!"<<endl;

  cout << calc(3, 5);

  Py_Finalize();

  return 0;
}

the sam2.py (normal python) is not imported and the error is

Exception NameError: "name 'sam2' is not defined" in 'sam1.calc' ignored

Could you please let me know what is missing?

标签: python cython
1条回答
爷、活的狠高调
2楼-- · 2019-09-14 18:58

Problem 1 is that your module initialization function is failing. In Python 3 you need to test the output against NULL, and then print the error (if it occurred):

PyObject* m = PyInit_sam1();
if (m==NULL) {
    cout << "Module initialization failed!\n";
    if (PyErr_Occurred()) {
        PyErr_Print();
    }
}

(I'm not 100% sure what you do for Python2 since I think it doesn't return anything. Probably just PyErr_Occurred). This tells you:

Traceback (most recent call last):

File "sam1.pyx", line 2, in init sam1 (sam1.cpp:1094)

import sam2

ModuleNotFoundError: No module named 'sam2'

This traceback hopefully gives you the clue you need - it's not finding sam2. This is because the current directory isn't on the path by default for C api programs. You need to set it up so that it is - the following code goes after Py_Initialize but before the module initialization:

PyObject* path = PySys_GetObject("path");
// append "." to the path
PyObject* result = PyObject_CallMethod(path,"append","(s)",".");
Py_XDECREF(result);
// don't decref path though - it's borrowed

It gets sys.path and appends . to it. After that everything works fine.


Note - if you call your program from a different directory then "." refers to the wrong place. If this is the case then you need to do something cleverer and work out the fill path to the directory, probably from argv[0].

查看更多
登录 后发表回答