Cython 中的枚举成员名称重复 - 重新声明错误?

Posted

技术标签:

【中文标题】Cython 中的枚举成员名称重复 - 重新声明错误?【英文标题】:Duplicate enum member names in Cython - redeclaration error? 【发布时间】:2018-11-12 05:04:18 【问题描述】:

Cython 似乎不允许我重用枚举成员名称。

我正在尝试对以下枚举进行 cythonize:

from enum import Enum

class Fruit(Enum):

    UNKNOWN = 0
    APPLE = 1
    ORANGE = 2

class Animal(Enum):

    UNKNOWN = 0
    DOG = 1
    CAT = 2

但以下导致'UNKNOWN' redeclared编译错误:

cpdef enum Fruit:

    UNKNOWN = 0
    APPLE = 1
    ORANGE = 2    

cpdef enum Animal:

    UNKNOWN = 0
    DOG = 1
    CAT = 

我应该如何解决上述问题?

另外,我最好使用NULL 作为枚举成员名称,而不是UNKNOWN。但似乎NULL 是 Cython 的特权关键字,尽管它不适用于 CPython。有什么解决办法吗?

【问题讨论】:

【参考方案1】:

在 C 中,以下代码 would not compile:

enum Foo
    A
;

enum Bar
    A
;

因为在 C 中,枚举不会引入新的名称范围,因此如果您对 FooBar 两种类型使用相同的标识符 A,则会发生名称冲突。

Cython 会翻译(如果它只是应用其通常的方案并且不会因编译器错误而停止):

#foo.pyx
cpdef enum Fruit:
    UNKNOWN = 0   

cpdef enum Animal:
    UNKNOWN = 0

类似

enum __pyx_t_3foo_Fruit 
  __pyx_e_3foo_UNKNOWN = 0
;

enum __pyx_t_3foo_Animal 
  __pyx_e_3foo_UNKNOWN = 0
;

正如我们所见,这不是有效的 C,因此 Cython 的选择是生成错误。一个“问题”是 Cython 没有将类型名称(FruitAnimal)包含在生成的枚举值名称中,因此在 Cython 中,您可以将它们区分为 Fruit.UNKNOWN 和 @ 987654331@,它们将映射到相同的 C 标识符。

至少有两种选择:

A: C 中通常的策略是使用前缀来区分枚举,例如:

cpdef enum Fruit:
       FRUIT_UNKNOWN = 0

cpdef enum Animal:
      ANIMAL_UNKNOWN = 1

或 B:您可以让 Cython 完成这项工作,方法是将它们放在不同的 pxd 文件中,这些文件会导入到生成的 pyx 文件中:

# Fruit.pxd
cpdef enum Fruit:
    UNKNOWN = 0

#Animal.pxd
cpdef enum Animal:
    UNKNOWN = 0

# foo.pyx:
cimport Fruit
cimport Animal

# use Fruit.UNKNOWN and Animal.UNKNOWN

在生成的代码中,枚举名称将具有模块名称(即FruitAnimal),因此从 C 编译器的角度来看并不相同。

【讨论】:

感谢您的回答。如果 Python 版本在 CPython 上运行良好,我想有一些 hacky 方法来复制它?如果没有更好的方法,我会在 2 周内接受您的答复。

以上是关于Cython 中的枚举成员名称重复 - 重新声明错误?的主要内容,如果未能解决你的问题,请参考以下文章

类中成员声明的重新排序规则

java笔记java中的枚举(enum)和枚举类

Interface-Class允许静态成员方法到Instance成员方法重新声明,但Class-Class或Interface-Interface不允许[重复]

具有类名的数据成员

cython:C++ 方法声明中的 const 和 except

Cython 中的这个声明是啥? cdef PyObject **工人。它是指向指针的指针吗?