我是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的格式)。谁能给我一些指示?
答案 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)