如何在Cython中通过值访问枚举类型

6
我可以帮您翻译成中文。这段代码如下:

我手头拿到一些看起来像这样的代码:

在“header.hpp”文件中:

enum class my_enum_type {
    val1 = 0;
    ... 
}

在“header_lib.pyx”文件中:
cdef extern from "header.hpp":
    enum my_enum_type:
        val1 = 0;
        ...
...

稍后在“header_lib.pyx”中:
def foo():
    ...
    return my_enum_type.val1

我被告知这应该没有问题,但从我的经验来看,并不是这样的,正如在这篇文章中所示:在Cython代码中定义将用于C代码部分的枚举
然而,如果我写“return val1”,它也不能识别“val1”。正确的方法是什么?

你有检查下面的答案吗? - Saullo G. P. Castro
尝试使用 这个答案 来读取cpp文件并创建Enum - Ethan Furman
3个回答

9
您可以在Cython中声明一个枚举类型,如下所示:enum
ctypedef enum options: OPT1, OPT2, OPT3

或者

ctypedef enum options:
    OPT1,
    OPT2,
    OPT3

一个例子可能是:

def main():
    cdef options test
    test = OPT2
    f(test)

cdef void f(options inp):
    if inp == OPT1:
        print('OPT1')
    elif inp == OPT2:
        print('OPT2')
    elif inp == OPT3:
        print('OPT3')

当运行main()函数时,你将看到打印出"OPT2"。你可以像这里展示的cdef函数一样,将变量test传递给CC++函数。

6
注意,OP询问的是enum class而不是enum - Bjoern Dahlgren
我认为这种技术的问题在于你无法将字符串转换回原始的枚举类,在纯 Python 环境中没有“枚举”的概念,因此 Python 不能轻易地检查对象类型、枚举名称或基础值。 - ibarrond
@ibarrond 我还没有检查过,但我认为Python将枚举选项识别为整数值。不过这是个好观点... - Saullo G. P. Castro
没错,Cython枚举在Python级别上只是整数。 - ibarrond

5
为了保持Cython/C/C++枚举类和Python Enum类功能的双重性,我提出了一种镜像类的解决方案。该解决方案分为两个组件:
  1. On one side we have a Cython/C/C++ enum. This enum can either be originated by wrapping C/C++ code in an extern block...

     cdef extern from "header.h":
         enum my_c_enum_type:
             OPT1 = 0,
             OPT2,
             OPT3,
    

    ... or directly in Cython.

     ctypedef enum my_cy_enum_type:
         OPT1=0,    #Default value is 0
         OPT2,      #Default value is 1
         OPT3,      #Default value is 2
    
  2. On the other we have Python. Since Python 3.4, there is a supported class Enum that emulates that functionality (link to official documentation). Here we should replicate the enum elements in pure Python. You can make use of the auto function to fill the Enum just like in C/C++/Cython:

     from enum import Enum, auto
     class my_py_enum_type(Enum):
         OPT1=0
         OPT2=auto()
         OPT3=auto()
    
现在,要使用这个同时支持Python和Cython的解决方案:
    # PYTHON: we use the my_py_enum_type Enum
    enum_obj = my_py_enum_type(1)        # Corresponds to OPT2
    print(enum_obj.value, enum_obj.name) # We can access the value and the name 
    #> 1, OPT2
    s='OPT2'; enum_obj = getattr(my_py_enum_type, s) # We can create them from the string 'OPT2'


    # PYTHON TO CYTHON
    def func(enum_obj):
        if not isinstance(enum_obj, my_py_enum_type):
             raise TypeError
        # Use in a cython function that accepts only my_c_enum_type Cython enum
        myCythonEnumFunc(enum_obj.value) # Convert to C/Cython enum using value
        ...

    # CYTHON TO PYTHON
    def func():
        # a Cython enum
        cdef my_c_enum_type cy_enum_obj = val1
        # creating a python enum
        return my_p_enum_type(cy_enum_obj)  # Convert using the full cy_enum
        ...

该解决方案将Cython/C枚举类型(在Python中只是整数)转换为具有相同特性的Python枚举类,并将Python枚举对象中的值转换回原始的Cython类。您可以获得两全其美的最佳效果!


2
您可以使用cpdef在Cython中直接创建Python枚举:
cpdef enum my_enum_type:
    val1 = 0
    ...

这个只在文档中简短提到了一下(搜索cpdef enum


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接