我正在使用Cython编写程序。我有用Cython编写的cdef类(扩展类型)。我的扩展类型中的某些方法使用其他扩展类型(对象)的实例作为参数。我还希望能够将指针传递给我的扩展类型,并将这些指针存储在向量中。尝试编译时,出现错误,提示无法将这些扩展转换为Python对象。我可以将基本类型的实例(例如3(int
的实例))作为参数传递,但我自己定义的都没有。
以下内容说明了我想要在C ++中将对象作为参数传递的内容:
class Bar {
// ...
};
class Foo{
void ffoo(Bar arg){
// ...
}
};
以下内容在cython中进行了说明,但不正确:
cdef class Bar:
# ...
cdef class Foo:
cdef void ffoo(self, Bar arg):
# ...
以下内容说明了我想要在C ++中将对象作为参数传递的内容:
class Base {
// ...
};
class Derived : public Base {
// ...
};
class Foo{
void ffoo(Base* arg){
// ...
std::vector<Base*> internal_vec;
}
};
在问题的结尾,我尝试这样做。
基本上,我需要将类Bar
的实例作为参数传递。 (请参见下面的首次尝试)
我还想存储一个指向基本类型的指针向量。
这可能吗?
我已经检查了Cython文档,博客以及有关StackOverflow的类似问题,但似乎无法使这个非常基本的功能正常工作。
下面是我的尝试。
setup.py
from setuptools import setup, Extension
from Cython.Build import cythonize
pkg_name = 'soquestion'
compile_args = []
bar = Extension(
name=pkg_name + '.bar',
sources=[
pkg_name + '/bar.pyx',
],
language='c++',
extra_compile_args=compile_args,
)
foo = Extension(
name=pkg_name + '.foo',
sources=[
pkg_name + '/foo.pyx',
],
language='c++',
extra_compile_args=compile_args,
)
setup(
name=pkg_name,
ext_modules=cythonize(bar,
annotate=True,
build_dir='build') \
+ cythonize(foo,
annotate=True,
build_dir='build'),# \
packages=[
pkg_name
],
)
bar.pxd
cdef class Bar(object):
cdef int i
bar.pyx
cdef class Bar(object):
def __cinit__(self):
pass
def __init__(self):
pass
名称对象还可以用于将某些内容明确声明为 Python对象。
foo.pxd
from soquestion.bar cimport Bar
cdef class Foo(object):
cpdef void ffoo(self, object arg)
foo.pyx
from soquestion.bar cimport Bar
cdef class Foo(object):
cpdef void ffoo(self, object arg):
# obviously, cython would have to know that arg has member i
arg.i = 3
print(arg.i)
输出
>>> from soquestion.bar import Bar
>>> from soquestion.foo import Foo
>>> a = Bar
>>> b = Foo
>>> b.ffoo(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor 'ffoo' requires a 'soquestion.foo.Foo' object but received a 'type'
(我有点懒,但是派生类仍然应该能够保存指向基本类型的指针的向量。)
setup.py
from setuptools import setup, Extension
from Cython.Build import cythonize
pkg_name = 'soquestion'
compile_args = []
bar = Extension(
name=pkg_name + '.bar',
sources=[
pkg_name + '/bar.pyx',
],
language='c++',
extra_compile_args=compile_args,
)
foo = Extension(
name=pkg_name + '.foo',
sources=[
pkg_name + '/foo.pyx',
],
language='c++',
extra_compile_args=compile_args,
)
derived = Extension(
name=pkg_name + '.derived',
sources=[
pkg_name + '/derived.pyx',
],
language='c++',
extra_compile_args=compile_args,
)
setup(
name=pkg_name,
ext_modules=cythonize(bar,
annotate=True,
build_dir='build') \
+ cythonize(foo,
annotate=True,
build_dir='build'), \
+ cythonize(derived,
annotate=True,
build_dir='build') \
packages=[
pkg_name
],
)
bar.pxd
cdef class Bar(object):
cdef int i
bar.pyx
cdef class Bar(object):
def __cinit__(self):
pass
def __init__(self):
pass
foo.pxd
cdef class Foo(object):
cpdef void ffoo(self, object arg)
foo.pyx
cdef class Foo(object):
cpdef void ffoo(self, object arg):
# obviously, cython would have to know that arg has member i
arg.i = 3
print(arg.i)
derived.pxd
from libcpp.vector cimport vector
from soquestion.bar cimport Bar
cdef class Derived(Bar):
cdef vector[Bar*] vec
cdef void store_ptr(self, Bar* b)
derived.pyx
from libcpp.vector cimport vector
from soquestion.bar cimport Bar
cdef class Derived(Bar):
def __cinit__(self):
pass
def __init__(self):
pass
cdef void store_ptr(self, Bar* b):
self.vec.push_back(b)
输出
在出现Bar *
的每一行上,我得到
soquestion/derived.pxd:5:20: Pointer base type cannot be a Python object
答案 0 :(得分:0)
这基本上应该是您编写的方式。 Python(以及Cython)需要一个显式的self
参数,这与C ++具有一个隐式的this
参数是不同的。
cdef class Foo:
cdef void ffoo(self, Bar arg):
pass
您无需键入self
,因为Cython可以解决此问题。
就您的示例而言:无需继承object
-cdef class
仍然是Python对象。我认为这没有什么害处,但是可能会带来一些意想不到的后果。
在您的第一个示例中,它失败了,因为您传递了类型对象而不是Python实例。 这是您对Python的理解的一个基本错误,与Cython无关。。调用类型对象以创建实例:
>>> a = Bar()
>>> b = Foo()
>>> b.ffoo(a)
您的第二个示例正在尝试使用C ++容器存储cdef class
实例的集合。这是可能的,但是它比您想象的要复杂得多。除其他事项外,您还需要非常小心地进行引用计数。如果Bar*
是Bar
,则Cython不会识别cdef class
。只需使用Python列表即可。