使用fromkeys和Struct元组化OrderdDict

时间:2017-10-03 19:13:28

标签: python python-3.x struct metaprogramming ordereddictionary

我是python中元编程的新手。我想做类似以下的事情:

from struct import Struct, error as StructError
from collections import OrderedDict
from typing import List, Hashable
from uuid import UUID

class StructBytes(type):

    def __prepare__(name, bases, **kwds):
        return OrderedDict()

    # return a subclass/modification of OrdereDict with predefined keys and a Struct(fmt)
    # __init__ should fill key values from Struct.unpack(bytes)
    # in principle (although not necessary), this is a frozen ordered dict

...

class ThisFormat(metaclass=StructBytes, keys: List[Hashable], fmt: str)

    def __init__(some_bytes: bytes)
        try:
            # call to __init__ should use specified formatting
        except StructError:
            # some_bytes not valid for this class 
        else:
            # do post-processing on some field values, like:
            self['uuid'] = UUID(bytes=self['uuid'])

for some_bytes in buffer:
    structured = ThisFormat(some_bytes)
    structured[field] # returns post-processed bytes

但此时我不确定如何实施它。我看到元编程的原因是存在ThisFormat的多个版本,每个版本都有特定的字段键和字节结构(即Struct的格式)。谁能给我一些指示?

1 个答案:

答案 0 :(得分:0)

找到一个更直接的解决方案(例子):

from struct import Struct, error as StructError
from collections import OrderedDict
from typing import *


class StructBytes(Mapping[Hashable, Any]):
    __fields__: List[Hashable]
    __struct__: Struct

    def __init__(self, bytestring: bytes):
        try:
            values = self.__struct__.unpack(bytestring)
        except StructError as e:
            raise ValueError("invalid bytestring for formatting") from e
        else:
            self.__dict__ = OrderedDict(zip(self.__fields__, values))
            for f in self.__fields__:
                if f not in self:
                    raise KeyError("failed to retrieve field '{}'".format(f))

    def __getitem__(self, key) -> Any:
        return self.__dict__[key]

    def __iter__(self) -> Iterator:
        return iter(self.__dict__)

    def __len__(self) -> int:
        return len(self.__dict__)

    def __repr__(self) -> str:
        return repr(self.__dict__)

    def keys(self) -> KeysView:
        return self.__dict__.keys()

    def values(self) -> ValuesView:
        return self.__dict__.values()

    def items(self) -> ItemsView:
        return self.__dict__.items()


class UART(StructBytes):
    __fields__ = ['header length', 'payload length', 'protocol version',
                  'packet count', 'packet id']
    __struct__ = Struct("<BBBHB")

    def __init__(self, bytestring: bytes):
        super(UART, self).__init__(bytestring)
        if self['packet id'] == 0x06:
            self.__dict__['packet id'] = "EVENT_PACKET"
        else:
            raise NotImplementedError("undefined packet type")


uart = (
    b'\x06'  # header length
    b'\x38'  # payload length
    b'\x01'  # version
    b'\x8D\x97'  # packet counter
    b'\x06'  # packet id
)
test = UART(uart)