Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带有类方法的Cython回调 我开始使用Cython来将一些C++代码与Python接口。由于我需要在C++中做一些异步数据获取,所以我计划使用C++代码中的回调到Python。到目前为止,我已经成功地从C++调用Python函数,但是,我不能从C++调用Python类方法。我在StackOverflow上看到过一些关于它的问题,但是没有人能为一件看似简单的事情提供一个简单的答案。这是一个工作玩具的例子_Python_C++_Methods_Callback_Cython - Fatal编程技术网

带有类方法的Cython回调 我开始使用Cython来将一些C++代码与Python接口。由于我需要在C++中做一些异步数据获取,所以我计划使用C++代码中的回调到Python。到目前为止,我已经成功地从C++调用Python函数,但是,我不能从C++调用Python类方法。我在StackOverflow上看到过一些关于它的问题,但是没有人能为一件看似简单的事情提供一个简单的答案。这是一个工作玩具的例子

带有类方法的Cython回调 我开始使用Cython来将一些C++代码与Python接口。由于我需要在C++中做一些异步数据获取,所以我计划使用C++代码中的回调到Python。到目前为止,我已经成功地从C++调用Python函数,但是,我不能从C++调用Python类方法。我在StackOverflow上看到过一些关于它的问题,但是没有人能为一件看似简单的事情提供一个简单的答案。这是一个工作玩具的例子,python,c++,methods,callback,cython,Python,C++,Methods,Callback,Cython,myclass.h: \ifndef MYCLASS\u H #定义MYCLASS_H #定义PY_-SSIZE_-T_-CLEAN #包括 typedef void(*callbackfun)(PyObject*obj); 类MyClass { 公众: void start(callbackfun user_func,PyObject*obj); }; #endif//MYCLASS\u H myclass.cpp: #包括“myclass.h” void MyClass::start(ca

myclass.h:

\ifndef MYCLASS\u H
#定义MYCLASS_H
#定义PY_-SSIZE_-T_-CLEAN
#包括
typedef void(*callbackfun)(PyObject*obj);
类MyClass
{
公众:
void start(callbackfun user_func,PyObject*obj);
};
#endif//MYCLASS\u H
myclass.cpp:

#包括“myclass.h”
void MyClass::start(callbackfun user_func,PyObject*obj)
{
用户函数(obj);
}
PyMyClass.pyx:

<代码> diditul:语言= C++ #cython:language_level=3 “myclass.h”中的cdef外部程序: ctypedef void(*callbackfun)(对象对象对象) cdef cppclass MyClass: MyClass() 无效开始(调用运行用户函数,对象对象对象) cdef无效回调(自): 打印('回拨') cdef类PyMyClass: cdef MyClass*c_MyClass_ptr 定义(自我): self.c_myClass_ptr=new myClass() def uu dealoc uu(自我): del self.c_myClass_ptr def启动(自): self.c_myClass_ptr.start(回调,self) main.py:

从PyMyClass导入PyMyClass
def main():
myClass=PyMyClass()
myClass.start()
如果名称=“\uuuuu main\uuuuuuuu”:
main()
现在,如果我将
PyMyClass.pyx
中的
callback
函数转换为一个方法,如下所示:

PyMyClass.pyx:

<代码> diditul:语言= C++ #cython:language_level=3 “myclass.h”中的cdef外部程序: ctypedef void(*callbackfun)(对象对象对象) cdef cppclass MyClass: MyClass() 无效开始(调用运行用户函数,对象对象对象) cdef类PyMyClass: cdef MyClass*c_MyClass_ptr 定义(自我): self.c_myClass_ptr=new myClass() def uu dealoc uu(自我): del self.c_myClass_ptr cdef无效回调(自): 打印('回拨') def启动(自): self.c_myClass_ptr.start(self.callback,self) 现在编译器抱怨:

Compiling PyMyClass.pyx because it changed.
[1/1] Cythonizing PyMyClass.pyx

Error compiling Cython file:
------------------------------------------------------------
...

    cdef void callback(self):
        print('Called back')

    def start(self):
       self.c_myClass_ptr.start(self.callback, self)                                   ^
------------------------------------------------------------

PyMyClass.pyx:24:36: Cannot assign type 'void (PyMyClass)' to 'callbackfun'
Traceback (most recent call last):
  File "setup.py", line 22, in <module>
    setup(ext_modules = cythonize(ext_modules))
  File "/Users/andreac/anaconda3/lib/python3.7/site-packages/Cython/Build/Dependencies.py", line 1097, in cythonize
    cythonize_one(*args)
  File "/Users/andreac/anaconda3/lib/python3.7/site-packages/Cython/Build/Dependencies.py", line 1220, in cythonize_one
    raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: PyMyClass.pyx
正在编译PyMyClass.pyx,因为它已更改。
[1/1]Cythonizing PyMyClass.pyx
编译Cython文件时出错:
------------------------------------------------------------
...
cdef无效回调(自):
打印('回拨')
def启动(自):
self.c_myClass_ptr.start(self.callback,self)^
------------------------------------------------------------
PyMyClass.pyx:24:36:无法将类型“void(PyMyClass)”分配给“callbackfun”
回溯(最近一次呼叫最后一次):
文件“setup.py”,第22行,在
设置(ext_模块=cythonize(ext_模块))
cythonize中的文件“/Users/andreac/anaconda3/lib/python3.7/site packages/Cython/Build/Dependencies.py”,第1097行
cythonize_one(*args)
cythonize_one中的文件“/Users/andreac/anaconda3/lib/python3.7/site packages/Cython/Build/Dependencies.py”,第1220行
raise编译器错误(无,pyx_文件)
Cython.Compiler.Errors.CompileError:PyMyClass.pyx

这个问题有(简单的)解决方法吗?(是的,我知道使用
PyObject*
)还有一个潜在的引用计数问题。

您有一些问题,但它们相对容易解决:

  • self.callback
    正在尝试用
    self
    指针绑定函数。我不能100%确定在这种情况下它是如何工作的——它最终可能会创建一个可调用的Python
    对象,但无论哪种方式,它都肯定与回调函数不匹配。将其更改为
    &PyMyClass.callback
    。我还添加了一个
    &
    ,因为Cython似乎需要它来了解情况

  • &PyMyClass.callback
    仍然与
    callbackfun
    的签名不匹配
    callbackfun
    需要一个泛型Python对象,而
    PyMyClass.callback
    的第一个参数被专门化为指向
    PyMyClass
    的底层C结构的指针。这是很容易解决的一个演员,给予

    self.c_myClass_ptr.start(<callbackfun>&PyMyClass.callback, self)
    
    self.c_myClass_ptr.start(&PyMyClass.callback,self)
    
    这种对基于
    PyObject
    的结构的转换是使用pythoncapi时的常见习惯用法,因此很好。不幸的是,强制转换最终可能会隐藏错误,所以要小心

  • 你有一个潜在的引用计数灾难:你把一个“借来的引用”传递给
    self
    。您在问题中提到了这一点,但我将再次重复,以防将来的读者错过它(正如我在第一次浏览时所做的那样)。在这种情况下,您可以立即使用
    self
    ,然后丢弃它。但是,如果你将它保存在C++代码中,那么它可能会被破坏,而C++代码则会有一个有效的指针。设置回调时,这确实需要一个
    Py_INCREF
    ,取消设置回调时需要一个
    Py_DECREF
    。确保这种情况发生可能很难做到正确