如何将包装类的对象用作包装函数中的参数

时间:2019-09-23 12:26:59

标签: python c++ cython cythonize

我使用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”,但这不起作用。相同的错误不断发生。所有文件都在同一目录中。

1 个答案:

答案 0 :(得分:1)

很明显,这个问题只是一系列小问题,有些事情几乎可以解决:

  1. 最初的主要问题是函数[应为defcpdef,但不能cdef从Python调用 (Importing cython function: AttributeError: 'module' object has no attribute 'fun')。值得记住的是,Cython可以编译/加速所有功能,而cdefcpdef的唯一优势是可以从Cython稍快地调用它们。因此,默认情况下,您应该声明函数cdef

  2. 在某些情况下,您使用的是C ++类型名称Settings而不是Cython类PySettings。我认为这主要是错字。

  3. 在Settings.pyx中无需执行cimport Settings,在Helper.pyx中无需执行cimport Helper-Cython会自动执行from filename cimport *的等效操作,其中具有匹配项的.pxd文件文件名存在。

  4. 您的最后一个问题是将您的类分成多个文件-您无法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属性的事实。