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

2024-07-06 23:42:26 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

但故事还在继续。esmèU类子字段根据其所使用的消息类型具有不同的含义。你知道吗

现在出现了几个问题:

  1. 组织不同常数的最佳方法是什么?你知道吗
  2. 如何为同一字段(或子字段)定义不同的常量?你知道吗
  3. 为每个常量添加描述的最佳方法是什么?你知道吗

对于问题3,我选择了元组:CONST\u NAME=(0x01,'值含义',)。你知道吗

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

  • 你知道吗常量.esm\u类它包含所有esm\U类值
  • 你知道吗常数.数据\u编码包含所有可能的编码
  • etc(对于每个字段,一个常量模块)

对于数据单元编码,这很有效。但是esmèU类实际上由“子字段”组成。所以我想:

  • 你知道吗常量.esm\u类。消息类型子字段的类型
  • 你知道吗常量.esm\u类。消息模式的模式
  • 你知道吗常量.esm\u类特性字段的特性

这已经是相当长的时间,导致常量.esm\u类.features.UDHI\u和\u REPLAY\u路径例如。不知怎么的,不是很好。这还不是我所需要的。。。事实上,我甚至需要分钱常量.esm\u类.types分开,因为类型值在不同的上下文中有不同的含义(基本上是传入的消息和传出的短消息)。因此,如果我遵循模式,这将产生更多的子模块:常量.esm\u类.类型.传出以及常量.esm\u类.类型.传入你知道吗

另外,我还需要一种连接类型、模式和特性的方法来创建esm\u类值,并且我还需要将esm\u类分开进行解析。因此,需要有一种通用的方法来从常量构建字段值,并检测某个值是否非法(即,某个值不是由常量定义的)。你知道吗

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

编辑:我打算将lib与python3.3+一起使用,可能我想使其与2.7兼容,因此不幸的是,python3.4中的枚举没有解决方案。你知道吗

编辑2:可能我在太少的文本中压缩了太多的信息。所以我举个例子。你知道吗

SMPP中的esm\ U类是一种派生值,由类型、模式和特征组成。例如,如果esmèu类的值为00111100,实际上意味着feature等于00,mode等于1111,type等于00。这就是我所说的“子类型”。常量将与按位运算放在一起。你知道吗


Tags: 模块方法消息类型编码定义模式常数
1条回答
网友
1楼 · 发布于 2024-07-06 23:42:26

我将试着给出一个答案(我希望我正确地理解了你)。详细阐述我的上述评论,我会说:

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)

现在,代码当然可以优化,但关键是:我试图尽快抽象出二进制表示,以便得到表示协议中出现的结构的类层次结构。因此,我没有简单地将常量/值放在不同的模块中,而是以这样的方式组织它们,使它们与它们所属的结构一起出现——这也是您将在代码的其余部分中使用的结构。你知道吗

需要注意的其他事项:

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

  • 我通常会避免使用python3.4的枚举,因为当您需要访问符号的值(即它的value属性)时,它们很难处理,但这也是因为我不需要符号本身的名称。您的里程数可能会有所不同。

  • 最后,在上面的评论中,chepner就是否在代码中存储描述提出了一个非常好的观点。我建议你听从他的劝告。

相关问题 更多 >