首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用多个语义处理大量常量的最佳方法

使用多个语义处理大量常量的最佳方法
EN

Stack Overflow用户
提问于 2014-07-25 14:13:25
回答 1查看 124关注 0票数 0

我打算实现一个包含大量常量的库。现在已经有很多关于堆栈溢出上的常量的问题了。但是,我在思考一个使事情复杂化的特殊情况,我不知道该走哪条路。可能已经有人解决了类似的问题,可以帮助我避免明显的失败:)。

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

但故事还在继续。esm_class子字段有不同的含义,这取决于它们在其中使用的消息类型。

现在出现了几个问题:

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

对于问题3,我选择了tupels: CONST_NAME = (0x01,'value E足意‘)。

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

  • 包含所有constants.esm_class值的esm_class
  • constants.data_coding,它包含所有可能的编码
  • etc (每个字段都有一个常量模块)

对于data_coding来说,这很好。但是esm_class实际上是由‘子字段’组成的。所以我想:

  • 消息类型子字段的constants.esm_class.types
  • 消息模式的constants.esm_class.modes
  • 特性字段的constants.esm_class.features

这已经相当长了,例如,导致了constants.esm_class.features.UDHI_AND_REPLAY_PATH。不太好,不知怎么的。这还不是我所需要的..。实际上,我甚至需要将constants.esm_class.types分开,因为类型值在不同的上下文中有不同的含义(基本上是传入消息与传出短消息)。因此,如果我遵循模式: constants.esm_class.types.outgoing和constants.esm_class.types.incoming,就会产生更多的子模块。

此外,我还需要一种将类型、模式和特性连接起来以创建esm_class值的方法,还需要将esm_class拆分为两个部分进行解析。因此,需要有一种从常量构建字段值的通用方法,还需要检测某个值是非法的(即具有一个未由常量定义的值)。

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

编辑:--我打算在 3.3+中使用这个库,可能我想使它与2.7兼容,因此不幸的是,Python3.4中的Enum不是解决方案。

编辑2:可能用太少的文字包装了太多的信息。所以我会举一个例子。

SMPP中的esm_class是一种派生值,由类型、模式和特性组成。例如,如果esm_class的值为00111100,实际上它意味着该特性等于00,模式为1111,类型再次为00。这就是我所说的“子类型”。这些常量将与按位操作放在一起。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-07-25 15:58:30

我会尽力给出答案(我希望我对你的理解是正确的)。在阐述我的上述评论时,我想说的是:

代码语言:javascript
运行
复制
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对是否在代码中存储描述提出了一个非常好的观点。我建议你听从他的建议。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24957795

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档