Python 处理具有多个语义的大量常量的最佳方法

Python 处理具有多个语义的大量常量的最佳方法,python,Python,我打算实现一个包含大量常量的库。现在关于stackoverflow上的常量已经有很多问题了。但我正在考虑一个使事情复杂化的特殊情况,我不确定该怎么办。可能有人已经解决了类似的问题,可以帮助我避免明显的失败:) 更准确地说,我将实现SMPP(短消息p2p)相关的东西。SMPP由许多字段组成,这些字段具有不同的可能值,这些值有时由不同的部分组成。例如,esm_类字段为8位整数,位1-0、5-2和7-6为“子字段”。因此,值esm_类由三个“串联”在一起的常量组成 但故事还在继续。esm_类子字段具有

我打算实现一个包含大量常量的库。现在关于stackoverflow上的常量已经有很多问题了。但我正在考虑一个使事情复杂化的特殊情况,我不确定该怎么办。可能有人已经解决了类似的问题,可以帮助我避免明显的失败:)

更准确地说,我将实现SMPP(短消息p2p)相关的东西。SMPP由许多字段组成,这些字段具有不同的可能值,这些值有时由不同的部分组成。例如,esm_类字段为8位整数,位1-0、5-2和7-6为“子字段”。因此,值esm_类由三个“串联”在一起的常量组成

但故事还在继续。esm_类子字段具有不同的含义,具体取决于它们所使用的消息类型

现在出现了几个问题:

  • 组织不同常数的最佳方法是什么
  • 如何为同一字段(或子字段)定义不同的常量
  • 向每个常量添加描述的最佳方法是什么
  • 对于问题3,我选择了元组:CONST_NAME=(0x01,‘值的含义’,)

    对于其他问题,我的第一个想法是在模块中组织常量。例如,这将为我们提供:

    • constants.esm_类,其中包含所有esm_类值
    • constants.data\包含所有可能编码的编码
    • etc(对于每个字段,以常量表示的模块)
    对于数据编码,这很有效。但esm_类实际上由“子字段”组成。所以我想:

    • 消息类型子字段的constants.esm_class.types
    • 消息模式的constants.esm_class.modes
    • 特性字段的constants.esm_class.features
    这已经相当长了,例如,生成了constants.esm_class.features.UDHI_和_REPLAY_PATH。不知怎么的,不是很好。这还不是我所需要的。。。实际上,我甚至需要将constants.esm_class.types分开,因为类型值在不同的上下文中有不同的含义(基本上是传入消息和传出短消息)。因此,如果我遵循模式,这将产生更多的子模块:constants.esm_class.types.outing和constants.esm_class.types.incoming

    此外,我还需要一种连接类型、模式和功能的方法来创建esm_类值,并且我还需要将esm_类拆分以进行解析。因此,需要有一种通用的方法来从常量构建字段值,并检测某个值是否非法(即,该值未由常量定义)

    我的问题:你认为我应该遵循的最佳方式是什么?我应该去上课吗?正如我所读到的,python的最佳实践是在模块级定义常量。我还看到了一些使用类的问题。那么,每个可能字段的新数据类型是否可以做到这一点?我被卡住了,期待着你的想法

    Edit:我打算在python 3.3+中使用lib,可能我想使其与2.7兼容,因此遗憾的是,python 3.4中的枚举没有解决方案

    编辑2:可能我在太少的文本中压缩了太多的信息。因此,我将举一个例子


    SMPP中的esm_类是一种派生值,由类型、模式和特征组成。例如,如果esm_类的值为00111100,实际上意味着特征等于00,模式等于1111,类型等于00。这就是我所说的“子类型”。常量将与按位运算结合在一起。

    我将尝试给出一个答案(希望我正确理解了您的意思)。在详细阐述我的上述评论后,我会说:

    class esm_class:
        BITMASK_FEATURE = 0b11000000
        BITMASK_MODE    = 0b00111100
        BITMASK_TYPE    = 0b00000011
    
        class Features:
            FEATURE_1 = 0b00
            FEATURE_2 = 0b01
            FEATURE_3 = 0b10
            FEATURE_4 = 0b11
    
        class Modes:
            MODE_1 = 0b0000
            # …
    
        class Types:
            TYPE_1 = 0b00
            TYPE_2 = 0b01
            # …
    
        def __init__(self, type_, mode, feature):
            self.type = type_
            self.mode = mode
            self.feature = feature
    
        def __bytes__(self):
            '''
            Use this to write an instance of esm_class to a file-like 
            object or stream, e.g..: 
            mysocket.send(bytes(my_esm_class_obj))
            '''
            return ((self.feature << 6) | (self.mode << 2) |
                    self.type).to_bytes(1, byteorder='big')
    
        @classmethod
        def parse(cls, filelike):
            '''
            Use this to parse incoming data from a file-like object
            and create an instance of esm_class accordingly, e.g:
            my_esm_class_obj = esm_class.parse(stream)
            '''
            instance = cls()
            data = filelike.read(1)
            instance.feature = int.from_bytes((data & cls.BITMASK_FEATURE) >> 6)
            instance.mode = int.from_bytes((data & cls.BITMASK_MODE) >> 2)
            instance.mode = int.from_bytes((data & cls.BITMASK_TYPE) >> 2)
    
    等级esm\u等级:
    位掩码功能=0b11000000
    位掩码_模式=0b00111100
    位掩码类型=0b00000011
    课程特色:
    特征_1=0b00
    特征_2=0b01
    特征_3=0b10
    特征_4=0b11
    课程模式:
    模式_1=0b0000
    # …
    类别:
    类型_1=0b00
    类型_2=0b01
    # …
    定义初始化(自身、类型、模式、功能):
    self.type=type_
    self.mode=mode
    self.feature=特征
    定义字节(自):
    '''
    使用此选项将esm_类的实例写入如下文件
    对象或流,例如…:
    发送(字节(我的esm类obj))
    '''
    返回((self.feature 6)
    instance.mode=int.from_字节((数据和cls.BITMASK_模式)>>2)
    instance.mode=int.from_字节((数据和cls.BITMASK_类型)>>2)
    
    现在,代码当然可以优化,但关键是:我试图尽快抽象出二进制表示,以获得表示协议中出现的结构的类层次结构。因此,我没有简单地将常量/值放在不同的模块中,而是以这样的方式组织它们,即它们与它们所属的结构一起出现——这也是您将在其余代码中使用的结构

    需要注意的其他事项:

    • 如果您愿意,您当然可以省略类
      功能
      模式
      类型
      ,并将所有值放在
      esm_类
      的范围内。但是,只有当符号的名称
      功能_1
      模式_2
      等明确表示它们对应于位字符串的哪一部分时,我才会这样做(即特征部件或模式部件或…)

    • 我通常会避免使用Python 3.4的枚举,因为在我看来,当您需要访问符号的值(即它的
      属性)时,它们的处理非常繁琐,但这也是因为我不需要符号本身的名称。您可能会有所不同

    • 最后,在上面的评论中,chepner就是否存储描述i提出了一个非常好的观点