也许我已经找到了这个问题的答案,因为它不可能,但如果有一个漂亮的伎俩......我全都耳朵。我试图在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风格枚举,还是我坚持用它来复制它?
答案 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
,它有一些额外的好处(例如基于类的NamedTuple
和Constant
类)。< / 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>