PEP 593 introduced typing.Annotated. I’ve been trying to wrap my head around how it’s supposed to be used, and I can’t make sense of it. Having read PEP 593, the discussions that preceded it [1][2], and the documentation on Annotated, I still do not understand how Annotated is meant to be used.
The first example in the PEP is
UnsignedShort = Annotated[int, struct2.ctype('H')]
SignedChar = Annotated[int, struct2.ctype('b')]
class Student(struct2.Packed):
# mypy typechecks 'name' field as 'str'
name: Annotated[str, struct2.ctype("<10s")]
serialnum: UnsignedShort
school: SignedChar
# 'unpack' only uses the metadata within the type annotations
Student.unpack(record)
# Student(name=b'raymond ', serialnum=4658, school=264)
The semantics of struct2 are not made clear, which prevents me from understanding the example [1].
I have tried to recreate something that behaves kind of like this example, and this is what I came up with:
import struct
from dataclasses import dataclass
from typing import Annotated
UnsignedShort = Annotated[int, struct.Struct("H")]
SignedChar = Annotated[int, struct.Struct("b")]
@dataclass
class Student:
name: Annotated[str, struct.Struct("<10s")]
serialnum: UnsignedShort
school: SignedChar
@classmethod
def unpack(cls, record: bytes) -> "Student":
unpacker = struct.Struct(
"".join(a.__metadata__[0].format for a in cls.__annotations__.values())
)
return cls(*unpacker.unpack(record))
record = b"raymond 2\x12@"
Student.unpack(record)
# Student(name=b'raymond ', serialnum=4658, school=64)
which works, but this line
"".join(a.__metadata__[0].format for a in cls.__annotations__.values())
is all kinds of awful. Is this really how I’m supposed to use Annotated at runtime?
Like, is
Studentsome kind of dataclass?name,serialnumber, andschooldo not seem to be class vars, despite syntactically appearing to be.struct2.Packedapparently provides anunpackmethod which, per the example, “only uses the metadata within the type annotations”. How? Also,school=264does not fit in aSignedChar. ↩︎