在 Python 中像枚举一样创建 C
Creating C like Enum in Python
也许我已经找到了这个问题的答案,因为这是不可能的,但如果有一个漂亮的把戏……我洗耳恭听。我正在尝试在 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 中使用 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()
函数,return 一个带有全局符号 table.
的字典
如果适用,请参阅 Python 3.4 的 Python documentation。我根据在这里找到的内容编写了代码。
这主要是一个 hack,因为我确信有更有效的方法来解决我所做的事情。
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 语句创建项目时的输出,它用于调试目的,但这是我获取数据的最佳方式。
有一个新的 aenum library by the author of enum34
,它有一些额外的好处(例如基于 class 的 NamedTuple
和 Constant
class)。
如果您使用 Python3,其中一个很酷的功能是内置的自动编号:
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>
也许我已经找到了这个问题的答案,因为这是不可能的,但如果有一个漂亮的把戏……我洗耳恭听。我正在尝试在 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 中使用 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()
函数,return 一个带有全局符号 table.
如果适用,请参阅 Python 3.4 的 Python documentation。我根据在这里找到的内容编写了代码。
这主要是一个 hack,因为我确信有更有效的方法来解决我所做的事情。
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 语句创建项目时的输出,它用于调试目的,但这是我获取数据的最佳方式。
有一个新的 aenum library by the author of enum34
,它有一些额外的好处(例如基于 class 的 NamedTuple
和 Constant
class)。
如果您使用 Python3,其中一个很酷的功能是内置的自动编号:
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>