在Python中创建类似C的枚举

在Python中创建类似C的枚举,python,c,enums,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, L

也许我已经找到了这个问题的答案,因为这是不可能的,但是如果有一个漂亮的把戏。。。我洗耳恭听。我试图在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风格枚举的巧妙方法,还是我一直在艰难地复制它?

也许你可以在python 3中使用一些C风格枚举的变体。对于Python2,我只做了以下操作(在每行末尾加括号以避免出现难看的
\
):

要处理多个范围,只需使用多个单独的
range()。缺点是必须显式指定最终值

中似乎也有一些更奇特的方法,但上面的方法应该最接近C风格的
enum
,语法开销最小

这不是一个严肃的建议,但如果您喜欢神秘的代码和有问题的做法,那么下面的破解似乎也适用于C风格的
枚举
(需要注意的是,枚举数总是在模块范围内创建的)。你可以尽情地唠叨

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

如果适用,请参阅适用于Python 3.4的。我是根据我在这里找到的东西写代码的

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

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 = ()
   # ...
此“枚举”输出有效地包括:

0x00 # NONE
0x01
0x02
...
0x10000 # START_SENDING_PICTURES
0x10001
0x10002
...
0x20000 # VOLUME_REQUEST
0x20001
...
0x30000 # NEW_DELIVERY_REQ
0x30001
0x30002
...
注意,输出是在使用print语句创建项时产生的,它是为了调试目的,但这是我获得数据的最好方法。

作者的一个新方法有一些额外的优点(例如基于类的
NamedTuple
常量
类)

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

from aenum import Enum

class Id(Enum, start=0):
    #
    _auto_on_                   # needed since aenum 3.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>
打印(repr(Id.HEARTBEAT))
# 
打印(报告(Id.停止发送图片))
# 
打印(报告(Id.VOLUME_请求))
# 

I使用工作代码进行了更新。这主要是一个黑客攻击,但实际上是一个自我更新的枚举。我不太喜欢每次枚举后的
=()
,但这做了我想要的工作。谢谢谢谢我想这个和@Saturisk答案对我来说是有用的。我只需要选择我想用哪一个:)@David,我在发布之前确实看到了,但我认为它没有很好地满足我的具体要求。我相信下面的答案更适合这个特殊的要求。这里的答案是那里答案的一个子集,是对那里答案的一种苍白模仿。我建议你仔细阅读这些答案。我只是浏览了这些答案,但没有一个能回答OP的问题。如果您对我的证书感兴趣:我是的和的主要作者。这很酷,可能是最干净、最简单的解决方案,但我当时没有这个库。我相信我们只限于外部图书馆。不错的解决方案@Ethan:)@ls6777:谢谢!如果你喜欢,可以投赞成票我确实投了赞成票,但在我获得15个代表点之前,它不会公开显示;)啊,好的。谢谢@罗伯托:请提供更多细节——我刚刚用最新版本的aenum和Python进行了测试,效果很好。
from aenum import Enum

class Id(Enum, start=0):
    #
    _auto_on_                   # needed since aenum 3.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>