在Python中创建类似Enum的C语言

时间:2015-03-25 19:36:06

标签: python c enums

也许我已经找到了这个问题的答案,因为它不可能,但如果有一个漂亮的伎俩......我全都耳朵。我试图在python中重现以下C枚举列表:

enum Id
{
   NONE = 0,
   HEARTBEAT, //0x1
   FLUID_TRANSFER_REQUEST,
   FLUID_TRANSFER_STATUS_MSG,
   FLUID_TRANSFER_ERROR_MSG,
   FLUID_TRANSFER_RESUME,
   EMERGENCY_STOP_MSG,
   LOG_MSG,
   VERSION_REQUEST,
   VERSION_RESPONSE,
   CHANNEL_INFORMATION_REQUEST,
   CHANNEL_INFORMATION_RESPONSE,
   TEST_REQUEST,
   LED_CONTROL_REQ,
   RESET_REQ,

   // Camera App Messages
   START_SENDING_PICTURES = 0x010000,
   STOP_SENDING_PICTURES,
   START_RECORDING_VIDEO_REQ,
   STOP_RECORDING_VIDEO_REQ,
   TAKE_PICTURE_REQ,
   SET_VOLUME_LIMIT,         
   VIDEO_FRAME_MSG,
   PICTURE_MSG,
   I_FRAME_REQUEST,
   CURRENT_VOLUME,
   START_ANALYZING_IMAGES_REQ,
   STOP_ANALYZING_IMAGES_REQ,
   SET_FILE_PATH,

   //Sensor Calibration
   VOLUME_REQUEST = 0x020000,
   START_CAL,
   CLI_COMMAND_REQUEST,
   CLI_COMMAND_RESPONSE,

   // File Mananger
   NEW_DELIVERY_REQ = 0x30000,
   GET_DELIVERY_FILE_REQ,
   GET_FILE_REQ,

   ACK_NACK,
   RESPONSE,

   LAST_ID
};

但是,我不想指定列表的每个值,因为它经常更改。由于我也在各个部分设置了一个新值,我不能使用自动编号方法(例如VOLUME_REQUEST = 0x020000)。任何人都有一个巧妙的技巧来复制python中的C风格枚举,还是我坚持用它来复制它?

3 个答案:

答案 0 :(得分:2)

也许你可以在Python 3中使用this的一些变体。对于Python 2,我只是做了以下操作(用括号来避免每行末尾的丑陋\):

(T_OR, T_AND, T_NOT,
 T_OPEN_PAREN, T_CLOSE_PAREN,
 T_EQUAL, T_UNEQUAL,
 ...
 T_DEFCONFIG_LIST, T_MODULES, T_VISIBLE) = range(0, 39)

要处理多个范围,只需使用多个单独的range()分配即可。缺点是您必须明确指定最终值。

How can I represent an 'Enum' in Python?中似乎也有一些比较漂亮的方法,但上面应该最接近C风格enum,语法开销最小。

不是一个严肃的建议,但如果你喜欢含糊不清的代码和可疑的做法,那么下面的hack似乎也适用于C风格的enum(需要注意的是,枚举器总是在模块范围内创建)。随意竖琴。 ;)

def create_var_range(first_val, *names):
    for name in names:
        globals()[name] = first_val
        first_val += 1

create_var_range(0,
                 "NONE",
                 "HEARTBEAT",
                 ...)

create_var_range(0x010000,
                 "START_SENDING_PICTURES",
                 "STOP_SENDING_PICTURES",
                 ...)

create_var_range()逐步执行其变量参数名称列表,并为每个名称创建一个变量,从first_val开始分配递增的整数值。它使用globals()函数,该函数返回带有全局符号表的字典。

答案 1 :(得分:2)

如果适用,请参阅Python {的Python documentation。我根据我在这里找到的内容编写了代码。

这主要是一种黑客攻击,因为我确信有更有效的方法来解决我所做的事情。

尽管现在标记为重复,但我认为我至少可以解决您的问题。

from enum import IntEnum
import re

class AutoNumber(IntEnum):
    def __new__(cls, *args):
        numberList = re.findall(r'\d+', str(cls._member_map_))
        if len(cls.__members__) > 0 and not args:
            prevMax = max(map(int, numberList))
            value = prevMax + 1
            print(format(value, '#04x'))
        else:
            value = args[0]
            print(format(value, '#04x'))

        integer = int.__new__(cls)
        integer._value_ = value
        return integer

class EnumClass(AutoNumber):
   NONE = 0
   HEARTBEAT = () # 0x1
   FLUID_TRANSFER_REQUEST = ()
   # ...

   # Camera App Messages
   START_SENDING_PICTURES = 0x010000
   STOP_SENDING_PICTURES = ()
   START_RECORDING_VIDEO_REQ = ()
   # ...

   # Sensor Calibration
   VOLUME_REQUEST = 0x020000
   START_CAL = ()
   # ...

   # File Mananger
   NEW_DELIVERY_REQ = 0x30000
   GET_DELIVERY_FILE_REQ = ()
   GET_FILE_REQ = ()
   # ...

这个' enum'产出是有效的:

0x00 # NONE
0x01
0x02
...
0x10000 # START_SENDING_PICTURES
0x10001
0x10002
...
0x20000 # VOLUME_REQUEST
0x20001
...
0x30000 # NEW_DELIVERY_REQ
0x30001
0x30002
...

注意,输出是在使用print语句创建项目时,它是出于调试目的,但它是我可以获得数据的最佳方式。

答案 2 :(得分:1)

aenum library的作者有一个新的enum34,它有一些额外的好处(例如基于类的NamedTupleConstant类)。< / p>

如果您使用Python 3,可用的一个很酷的功能是内置自动编号:

from aenum import Enum

class Id(Enum, start=0):

    NONE  # 0x0
    HEARTBEAT  # 0x1
    FLUID_TRANSFER_REQUEST
    FLUID_TRANSFER_STATUS_MSG
    FLUID_TRANSFER_ERROR_MSG
    # ...

    # Camera App Messages
    START_SENDING_PICTURES = 0x010000
    STOP_SENDING_PICTURES
    START_RECORDING_VIDEO_REQ
    STOP_RECORDING_VIDEO_REQ
    # ...

    # Sensor Calibration
    VOLUME_REQUEST = 0x020000
    START_CAL
    CLI_COMMAND_REQUEST
    CLI_COMMAND_RESPONSE

    # File Mananger
    NEW_DELIVERY_REQ = 0x30000
    GET_DELIVERY_FILE_REQ
    GET_FILE_REQ

    ACK_NACK
    RESPONSE

    LAST_ID

并在使用中:

print(repr(Id.HEARTBEAT))
# <Id.HEARTBEAT: 1>

print(repr(Id.STOP_SENDING_PICTURES))
# <Id.STOP_SENDING_PICTURES: 65537>

print(repr(Id.VOLUME_REQUEST))
# <Id.VOLUME_REQUEST: 131072>