我使用cython包装C ++代码,并使其在Python中可用。我面临的问题是我想在我也想包装的函数中使用包装的类作为参数。因此,从Python的角度来看,我想创建和修改包装类的对象,并将其用作包装函数的参数,我也想从Python调用该包装函数。下面的代码有望证明这一点。
在下面,您可以找到我想包装的C ++最小示例:
./ cppCode / Settings / Settings.h
class Settings
{
public:
Settings();
void doSomething();
};
./ cppCode / Helper / Helper.h
#include "../Settings/Settings.h"
void myFunction(Settings settings);
功能并不是很重要。因此,我省略了.cpp文件。到目前为止,以下是我在Cython中使用的方法:
./ cythonCode / Settings / Settings.pxd
cdef extern from "../../cppCode/Settings/Settings.h":
cdef cppclass Settings:
Settings() except +
void doSomething()
./ cythonCode / Settings / Settings.pyx
# distutils: sources = ../../cppCode/Settings/Settings.cpp
# distutils: language = c++
from Settings cimport Settings
cdef class PySettings:
cdef Settings c_settings
def __cinit__(self):
self.c_settings = Settings()
def doSomething(self):
self.c_settings.doSomething()
./ cythonCode / Helper.pxd
from Settings.Settings cimport Settings
cdef extern from "../../cppCode/Helper/Helper.h":
void myFunction(Settings settings)
./ cythonCode / Helper.pyx
# distutils: sources = ../../cppCode/Helper/Helper.cpp
# distutils: language = c++
from Helper cimport myFunction
cdef PyMyFunction(PySettings settings):
myFunction(settings)
run.py
import cythonCode.Settings.Settings as Settings
#import cythonCode.Helper as Helper
mySettings = Settings.PySettings()
mySettings.doSomething()
#Helper.myFunction(mySettings) # not working
我希望项目的结构清晰。我实际上实际上也希望在文件夹“ Helper”中也有“ Helper.pyx”和“ Helper.pxd”,但是后来我不知道如何导入设置。如果您能帮助我解决此问题,也将不胜感激。但是,主要问题是要完全运行Helper,以便可以在“ run.py”中使用它。 构建cython模块的“ setup.py”看起来像这样:
from distutils.core import setup
from Cython.Build import cythonize
from setuptools.extension import Extension
extensions = [
Extension("Helper", ["Helper.pyx"])
]
setup(ext_modules=cythonize(extensions))
我在“设置”文件夹中分别进行同样的操作。
非常感谢您为解决此问题所提供的帮助!
编辑:如评论中所述,有两个错误:
1)它应该是run.py中的Helper.PyMyFunction(mySettings)。
2)在PyMyFunction前面应该是def而不是cdef,因为我确实想从Python调用此函数。
EDIT2 :我仔细研究了您的意见,发现了一个不好的解决方案,导致了另一个问题。所以下面是适合我的代码:
Settings.pxd
cdef extern from "../../cppCode/Settings/Settings.h":
cdef cppclass Settings:
Settings() except +
void doSomething()
cdef extern from "../../cppCode/Helper/Helper.h":
void myFunction(Settings settings)
Settings.pyx
# distutils: sources = [../../cppCode/Settings/Settings.cpp, ../../cppCode/Helper/Helper.cpp]
# distutils: language = c++
from Settings cimport Settings, myFunction
cdef class PySettings:
cdef Settings c_settings
def __cinit__(self):
self.c_settings = Settings()
def doSomething(self):
self.c_settings.doSomething()
def PyMyFunction(PySettings settings):
myFunction(settings.c_settings)
当我对Settings.pyx进行cythonize处理时,我可以运行以下Python代码,并且一切正常:
import Settings
mySettings = Settings.PySettings()
mySettings.doSomething()
Settings.PyMyFunction(mySettings)
我发现这很不雅致,因为两个部分(Settings和myFunction)都包含在同一文件中。当这两个部分位于单独的文件中时,我不知道如何运行它。
EDIT3 :为了解决“两个部分位于单独的文件中”的问题,请想象以下代码:
Settings.pxd
cdef extern from "../../cppCode/Settings/Settings.h":
cdef cppclass Settings:
Settings() except +
void doSomething()
Settings.pyx
# distutils: sources = ../../cppCode/Settings/Settings.cpp
# distutils: language = c++
from Settings cimport Settings
cdef class PySettings:
cdef Settings c_settings
def __cinit__(self):
self.c_settings = Settings()
def doSomething(self):
self.c_settings.doSomething()
Helper.pxd
from Settings cimport Settings
cdef extern from "../../cppCode/Helper/Helper.h":
void myFunction(Settings settings)
Helper.pyx
# distutils: sources = ../../cppCode/Helper/Helper.cpp
# distutils: language = c++
from Helper cimport myFunction
def PyMyFunction(PySettings settings):
myFunction(settings.c_settings)
与EDIT2中的代码相同,但分为两个文件。 Helper.pxd中只有另一行“来自设置cimport设置”。但是,在Helper.pyx中出现此错误:
def PyMyFunction(PySettings settings):
^
---------------------------------------
Helper.pyx:6:17: 'PySettings' is not a type identifier
我尝试“从设置cimport PySettings”,但这不起作用。相同的错误不断发生。所有文件都在同一目录中。
答案 0 :(得分:1)
很明显,这个问题只是一系列小问题,有些事情几乎可以解决:
最初的主要问题是函数[应为def
或cpdef
,但不能cdef
从Python调用
(Importing cython function: AttributeError: 'module' object has no attribute 'fun')。值得记住的是,Cython可以编译/加速所有功能,而cdef
或cpdef
的唯一优势是可以从Cython稍快地调用它们。因此,默认情况下,您应该声明函数cdef
。
在某些情况下,您使用的是C ++类型名称Settings
而不是Cython类PySettings
。我认为这主要是错字。
在Settings.pyx中无需执行cimport Settings
,在Helper.pyx中无需执行cimport Helper
-Cython会自动执行from filename cimport *
的等效操作,其中具有匹配项的.pxd文件文件名存在。
您的最后一个问题是将您的类分成多个文件-您无法cimport PySettings
进入Helper.pyx。您应该记住,“ cimport
”看着.pxd文件-有点像C / C ++头文件。如果要cimport PySettings
,则PySettings
(的声明)必须位于Settings.pxd
cdef class PySettings:
cdef Settings c_settings
# signatures for any cdef functions also go here
您在Settings.pyx中完成
cdef class PySettings:
# don't duplicate "cdef Settings c_settings"
# do put all the def functions here
def __cinit__(self):
self.c_settings = Settings()
def doSomething(self):
self.c_settings.doSomething()
从此Helper.pyx中将了解PySettings
及其具有c_settings
属性的事实。