3.2.1.2. Struct#
A struct describes a finite collection of named fields. In contrast to a sequence, a struct
utilizes Python classes as its model. The annotation feature in Python enables the definition of
custom types as annotations, enabling this special struct class to create a model solely based on
class annotations. Additionally, it generates a dataclass of the provided model, offering a
standardized string representation.
Several differences exist between a Sequence and a
Struct, with the most significant ones highlighted below:
Sequence |
Struct |
|
|---|---|---|
Model Type |
dict |
type |
Inheritance |
No |
Yes |
Attribute Access |
|
|
Unpacked Type (also needed to pack) |
dict [*] |
instance of model |
Documentation |
No |
Yes |
As evident from the comparison, the Struct class introduces new features such as
inheritance and documentation support. It’s crucial to note that inheritance uses
struct types exclusively.
The Sequence class implements a specific process for creating an internal representation
of the given model. The Struct class enhances this process by handling default values, replacing
types for documentation purposes, or removing annotation fields directly from the model. Additionally,
this class adds __struct__ to the model afterward.
Implementation Note
If you decide to use the annotation feature from the __future__ module, it is necessary to
enable S_EVAL_ANNOTATIONS since it “Stringizes” all annotations. inspect then
evaluates all strings, introducing a potential security risk. Exercise with caution when evaluating code!
Specifying structs is as simple as defining Python Classes:
>>> @struct
... class BaseFormat:
... magic: b"MAGIC"
... a: uint8
...
Internally, a representation with all required fields and their corresponding names is
created. As b"MAGIC" or uint8 are instances of types, the type replacement
for documentation purposes should be enabled, as shown in Special Methods for Struct-Like objects.
As described above, this class introduces an easy-to-use inheritance system using the method resolution order of Python:
>>> @struct
... class Format(BaseFormat):
... b: uint32
... c: uint16
...
>>> list(Format.__struct__.get_members())
['magic', 'a', 'b', 'c']
Programmers Note
As the Struct class is a direct subclass of Sequence, nesting is supported
by default. That means, so-called anonymous inner structs can be defined within a class
definition.
>>> @struct
... class Format:
... a: uint32
... b: {"c": uint8}
...
It is not recommended to use this technique as the inner structs can’t be used anywhere else.
Anonymous inner union definitions are tricky and are not officially supported yet. There are
workarounds to that problem, which are discussed in the API documentation of Sequence.