0

Je suis nouveau à la métaprogrammation en python. Qu'est-ce que je voudrais faire quelque chose de similaire à ce qui suit:métaclasse OrderdDict avec des touches et Struct

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 

Mais à ce stade, je ne suis pas sûr de savoir comment l'implémenter. La raison que je vois pour la métaprogrammation est que plusieurs versions de ThisFormat existent chacune avec des clés de champs spécifiques et une structure d'octets (c'est-à-dire un format pour Struct). Quelqu'un peut-il me donner quelques conseils?

Répondre

0

trouvé une solution plus simple (avec exemple):

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)