用 Cython 包装枚举 class
Wrap enum class with Cython
我正在尝试将枚举 class 包装在 C++ 头文件中以用于 cython 项目。
例如,这怎么能
enum class Color {red, green = 20, blue};
用 Cython 包裹。
CPP class
enum class Color {red, green = 20, blue};
类型定义
cdef extern from "colors.h":
cdef cppclass Color:
pass
颜色类型的定义
cdef extern from "colors.h" namespace "Color":
cdef Color red
cdef Color green
cdef Color blue
Python实施
cdef class PyColor:
cdef Color thisobj
def __cinit__(self, int val):
self.thisobj = <Color> val
def get_color_type(self):
cdef c = {<int>red : "red", <int> green : "green", <int> blue : "blue"}
return c[<int>self.thisobj]
这是一个替代解决方案,它使用更改 cython 和 C++ 标识符的名称的能力。
header.hpp
namespace foo {
enum class Bar : uint32_t {
BAZ,
QUUX
};
}
header.pxd
cdef extern from "header.hpp" namespace "foo::Bar":
cdef enum Bar "foo::Bar":
BAZ,
QUUX
main.pyx
from header cimport *
cdef void doit(Bar b):
pass
doit(BAZ) # Not Bar.BAZ, which would have been nicer.
它有效地告诉 cython 存在一个名为 "foo::Bar" 的命名空间,并将 C 风格的枚举放入其中。为了抵消 Bar 否则会变成 "foo::Bar::Bar" 的事实,它也被赋予了一个覆盖的名称。它确实意味着 Bar::BAZ 在 cython 中被称为 BAZ,而不是 Bar.BAZ,后者是枚举 类 的更惯用的表示,但它似乎足够接近。
另一种允许使用 PEP-435 Enums as mentioned in Cython docs 的方法如下:
foo.h
namespace foo {
enum class Bar : uint32_t {
Zero = 0,
One = 1
};
}
foo.pxd
from libc.stdint cimport uint32_t
cdef extern from "foo.h" namespace 'foo':
cdef enum _Bar 'foo::Bar':
_Zero 'foo::Bar::Zero'
_One 'foo::Bar::One'
cpdef enum Bar:
Zero = <uint32_t> _Zero
One = <uint32_t> _One
main.pyx
from foo cimport Bar
print(Bar.Zero)
print(Bar.One)
# or iterate over elements
for value in Bar:
print(value)
最新的 cython (3.x) 直接支持 c++ enum class
,记录在这里:
https://cython.readthedocs.io/en/latest/src/userguide/wrapping_CPlusPlus.html#scoped-enumerations
这是一个例子:
// cpp header
enum class State: int
{
Good,
Bad,
Unknown,
};
const char* foo(State s){
switch (s){
case State::Good:
return "Good";
case State::Bad:
return "Bad";
case State::Unknown:
return "Unknown";
}
}
Cython 方面
cdef extern from "test.h":
cpdef enum class State(int):
Good,
Bad,
Unknown,
const char* foo(State s)
def py_foo(State s):
return foo(s)
致电py_foo(State.Good)
returnsb'Good'
我正在尝试将枚举 class 包装在 C++ 头文件中以用于 cython 项目。
例如,这怎么能
enum class Color {red, green = 20, blue};
用 Cython 包裹。
CPP class
enum class Color {red, green = 20, blue};
类型定义
cdef extern from "colors.h":
cdef cppclass Color:
pass
颜色类型的定义
cdef extern from "colors.h" namespace "Color":
cdef Color red
cdef Color green
cdef Color blue
Python实施
cdef class PyColor:
cdef Color thisobj
def __cinit__(self, int val):
self.thisobj = <Color> val
def get_color_type(self):
cdef c = {<int>red : "red", <int> green : "green", <int> blue : "blue"}
return c[<int>self.thisobj]
这是一个替代解决方案,它使用更改 cython 和 C++ 标识符的名称的能力。
header.hpp
namespace foo {
enum class Bar : uint32_t {
BAZ,
QUUX
};
}
header.pxd
cdef extern from "header.hpp" namespace "foo::Bar":
cdef enum Bar "foo::Bar":
BAZ,
QUUX
main.pyx
from header cimport *
cdef void doit(Bar b):
pass
doit(BAZ) # Not Bar.BAZ, which would have been nicer.
它有效地告诉 cython 存在一个名为 "foo::Bar" 的命名空间,并将 C 风格的枚举放入其中。为了抵消 Bar 否则会变成 "foo::Bar::Bar" 的事实,它也被赋予了一个覆盖的名称。它确实意味着 Bar::BAZ 在 cython 中被称为 BAZ,而不是 Bar.BAZ,后者是枚举 类 的更惯用的表示,但它似乎足够接近。
另一种允许使用 PEP-435 Enums as mentioned in Cython docs 的方法如下:
foo.h
namespace foo {
enum class Bar : uint32_t {
Zero = 0,
One = 1
};
}
foo.pxd
from libc.stdint cimport uint32_t
cdef extern from "foo.h" namespace 'foo':
cdef enum _Bar 'foo::Bar':
_Zero 'foo::Bar::Zero'
_One 'foo::Bar::One'
cpdef enum Bar:
Zero = <uint32_t> _Zero
One = <uint32_t> _One
main.pyx
from foo cimport Bar
print(Bar.Zero)
print(Bar.One)
# or iterate over elements
for value in Bar:
print(value)
最新的 cython (3.x) 直接支持 c++ enum class
,记录在这里:
https://cython.readthedocs.io/en/latest/src/userguide/wrapping_CPlusPlus.html#scoped-enumerations
这是一个例子:
// cpp header
enum class State: int
{
Good,
Bad,
Unknown,
};
const char* foo(State s){
switch (s){
case State::Good:
return "Good";
case State::Bad:
return "Bad";
case State::Unknown:
return "Unknown";
}
}
Cython 方面
cdef extern from "test.h":
cpdef enum class State(int):
Good,
Bad,
Unknown,
const char* foo(State s)
def py_foo(State s):
return foo(s)
致电py_foo(State.Good)
returnsb'Good'