struct — Bytes als gepackte Binärdaten deuten

Quellcode: Lib/struct.py


Dieses Modul wandelt zwischen Python-Werten und C-Structs um, die als bytes-Objekte von Python dargestellt werden. Knappe Formatzeichenketten beschreiben die gewünschten Umwandlungen von und zu Python-Werten. Die Funktionen und Objekte des Moduls lassen sich für zwei weitgehend verschiedene Zwecke einsetzen: den Datenaustausch mit äußeren Quellen (Dateien oder Netzwerkverbindungen) oder die Datenübergabe zwischen der Python-Anwendung und der C-Ebene.

Bemerkung

Ist kein Präfixzeichen angegeben, gilt der native Modus. Er packt und entpackt Daten anhand der Plattform und des Compilers, mit denen der Python-Interpreter gebaut wurde. Das Ergebnis des Packens eines C-Structs enthält Füllbytes, die die richtige Ausrichtung der beteiligten C-Typen sicherstellen. Ebenso wird die Ausrichtung beim Entpacken berücksichtigt. Werden dagegen Daten mit äußeren Quellen ausgetauscht, liegt es beim Programmierer, Bytereihenfolge und Füllbytes zwischen den Elementen festzulegen. Näheres unter Bytereihenfolge, Größe und Ausrichtung.

Mehrere Funktionen von struct (und Methoden von Struct) nehmen ein Argument buffer. Gemeint sind Objekte, die Buffer-Protokoll umsetzen und entweder einen lesbaren oder einen les- und schreibbaren Puffer bereitstellen. Am häufigsten werden dafür die Typen bytes und bytearray verwendet, doch viele weitere Typen, die sich als Array von Bytes auffassen lassen, setzen das Pufferprotokoll um, sodass sie ohne zusätzliches Kopieren aus einem bytes-Objekt gelesen und gefüllt werden können.

Funktionen und Ausnahmen

Das Modul definiert die folgende Ausnahme und die folgenden Funktionen:

exception struct.error

Ausnahme, die bei verschiedenen Gelegenheiten ausgelöst wird. Das Argument ist eine Zeichenkette, die beschreibt, was nicht stimmt.

struct.pack(format, v1, v2, ...)

Gibt ein bytes-Objekt zurück, das die Werte v1, v2, … gemäß der Formatzeichenkette format gepackt enthält. Die Argumente müssen genau zu den Werten passen, die das Format verlangt.

struct.pack_into(format, buffer, offset, v1, v2, ...)

Packt die Werte v1, v2, … gemäß der Formatzeichenkette format und schreibt die gepackten Bytes ab der Position offset in den schreibbaren Puffer buffer. Beachte, dass offset ein verpflichtendes Argument ist. Ein negatives offset zählt vom Ende von buffer.

struct.unpack(format, buffer)

Entpackt aus dem Puffer buffer (der vermutlich mit pack(format, ...) gepackt wurde) gemäß der Formatzeichenkette format. Das Ergebnis ist auch dann ein Tupel, wenn es genau ein Element enthält. Die Größe des Puffers in Bytes muss der Größe entsprechen, die das Format verlangt und die calcsize() angibt.

struct.unpack_from(format, /, buffer, offset=0)

Entpackt aus buffer ab der Position offset gemäß der Formatzeichenkette format. Das Ergebnis ist auch dann ein Tupel, wenn es genau ein Element enthält. Die Größe des Puffers in Bytes ab der Position offset muss mindestens so groß sein, wie das Format verlangt und wie calcsize() angibt. Ein negatives offset zählt vom Ende von buffer.

struct.iter_unpack(format, buffer)

Entpackt schrittweise aus dem Puffer buffer gemäß der Formatzeichenkette format. Diese Funktion gibt einen Iterator zurück, der gleich große Stücke aus dem Puffer liest, bis sein gesamter Inhalt verbraucht ist. Die Größe des Puffers in Bytes muss ein Vielfaches der Größe sein, die das Format verlangt und die calcsize() angibt.

Jeder Schritt liefert ein Tupel, wie es die Formatzeichenkette angibt.

Added in version 3.4.

struct.calcsize(format)

Gibt die Größe des Structs (und damit des von pack(format, ...) erzeugten bytes-Objekts) zurück, die zur Formatzeichenkette format gehört.

Formatzeichenketten

Formatzeichenketten beschreiben die Anordnung der Daten beim Packen und Entpacken. Sie setzen sich aus Typcodes zusammen, die angeben, welche Art von Daten gepackt oder entpackt wird. Zusätzlich steuern besondere Zeichen Bytereihenfolge, Größe und Ausrichtung. Jede Formatzeichenkette besteht aus einem optionalen Präfixzeichen, das die allgemeinen Eigenschaften der Daten beschreibt, und einem oder mehreren Formatzeichen, die die eigentlichen Datenwerte und Füllbytes beschreiben.

Bytereihenfolge, Größe und Ausrichtung

Voreingestellt werden C-Typen im nativen Format und in der nativen Bytereihenfolge der Maschine dargestellt und richtig ausgerichtet, indem bei Bedarf Füllbytes eingefügt werden (nach den Regeln des C-Compilers). Dieses Verhalten ist so gewählt, dass die Bytes eines gepackten Structs genau der Anordnung des entsprechenden C-Structs im Speicher entsprechen. Ob native Bytereihenfolge und Füllbytes oder Standardformate zu verwenden sind, hängt von der Anwendung ab.

Andernfalls kann das erste Zeichen der Formatzeichenkette Bytereihenfolge, Größe und Ausrichtung der gepackten Daten angeben, gemäß der folgenden Tabelle:

Zeichen

Bytereihenfolge

Größe

Ausrichtung

@

nativ

nativ

nativ

=

nativ

standard

keine

<

Little-Endian

standard

keine

>

Big-Endian

standard

keine

!

Netzwerk (= Big-Endian)

standard

keine

Ist das erste Zeichen keines davon, wird '@' angenommen.

Bemerkung

Die Zahl 1023 (hexadezimal 0x3ff) hat die folgenden Byte-Darstellungen:

  • 03 ff in Big-Endian (>)

  • ff 03 in Little-Endian (<)

Python-Beispiel:

>>> import struct
>>> struct.pack('>h', 1023)
b'\x03\xff'
>>> struct.pack('<h', 1023)
b'\xff\x03'

Die native Bytereihenfolge ist je nach Hostsystem Big-Endian oder Little-Endian. Intel x86, AMD64 (x86-64) und Apple M1 sind zum Beispiel Little-Endian; IBM z und viele alte Architekturen sind Big-Endian. Mit sys.byteorder prüfst du die Bytereihenfolge deines Systems.

Native Größe und Ausrichtung werden mit dem Ausdruck sizeof des C-Compilers ermittelt. Das ist stets mit der nativen Bytereihenfolge verbunden.

Die Standardgröße hängt nur vom Typcode ab. Siehe die Tabelle im Abschnitt Typcodes.

Beachte den Unterschied zwischen '@' und '=': Beide verwenden die native Bytereihenfolge, bei letzterem sind Größe und Ausrichtung aber standardisiert.

Die Form '!' steht für die Bytereihenfolge im Netzwerk, die stets Big-Endian ist, wie in IETF RFC 1700 festgelegt.

Eine nicht native Bytereihenfolge lässt sich nicht angeben (Bytes also nicht erzwungen tauschen). Verwende dafür passend '<' oder '>'.

Hinweise:

  1. Füllbytes werden nur selbsttätig zwischen aufeinanderfolgenden Strukturelementen eingefügt. Am Anfang und am Ende des kodierten Structs werden keine Füllbytes eingefügt.

  2. Bei nicht nativer Größe und Ausrichtung, also etwa bei ‚<‘, ‚>‘, ‚=‘ und ‚!‘, werden keine Füllbytes eingefügt.

  3. Um das Ende einer Struktur an die Ausrichtungsanforderung eines bestimmten Typs anzupassen, beende das Format mit dem Code dieses Typs und einer Wiederholungszahl von null. Siehe Beispiele.

Typcodes

Typcodes (oder Formatcodes) haben die folgende Bedeutung. Die Umwandlung zwischen C- und Python-Werten dürfte angesichts der Typen auf der Hand liegen. Die Spalte „Standardgröße“ gibt die Größe des gepackten Werts in Bytes bei Verwendung der Standardgröße an, also wenn die Formatzeichenkette mit '<', '>', '!' oder '=' beginnt. Bei nativer Größe ist die Größe des gepackten Werts plattformabhängig.

Format

C-Typ

Python-Typ

Standardgröße

Hinweise

x

Füllbyte

kein Wert

(7)

c

char

bytes der Länge 1

1

b

signed char

int

1

(2)

B

unsigned char

int

1

(2)

?

_Bool

bool

1

(1)

h

short

int

2

(2)

H

unsigned short

int

2

(2)

i

int

int

4

(2)

I

unsigned int

int

4

(2)

l

long

int

4

(2)

L

unsigned long

int

4

(2)

q

long long

int

8

(2)

Q

unsigned long long

int

8

(2)

n

ssize_t

int

(2), (3)

N

size_t

int

(2), (3)

e

_Float16

float

2

(4), (6)

f

float

float

4

(4)

d

double

float

8

(4)

Zf

float complex

complex

8

(10)

Zd

double complex

complex

16

(10)

s

char[]

bytes

(9)

p

char[]

bytes

(8)

P

void*

int

(2), (5)

Geändert in Version 3.3: Unterstützung für die Formate 'n' und 'N' hinzugefügt.

Geändert in Version 3.6: Unterstützung für das Format 'e' hinzugefügt.

Geändert in Version 3.14: Unterstützung für die Formate 'F' und 'D' hinzugefügt.

Geändert in Version 3.15: Unterstützung für die Formate 'Zf' und 'Zd' hinzugefügt. Die Formate 'F' und 'D' sind soft deprecated.

Siehe auch

Die Module array und ctypes sowie Module von Dritten wie numpy verwenden ähnliche – aber leicht abweichende – Typcodes.

Hinweise:

  1. Der Umwandlungscode '?' entspricht dem Typ _Bool, den die C-Standards seit C99 definieren. Im Standardmodus wird er durch ein Byte dargestellt.

  2. Wird versucht, mit einem der Umwandlungscodes für ganze Zahlen etwas zu packen, das keine ganze Zahl ist, und hat dieses Objekt eine Methode __index__(), so wird diese Methode aufgerufen, um das Argument vor dem Packen in eine ganze Zahl umzuwandeln.

    Geändert in Version 3.2: Die Methode __index__() wird nun für Objekte verwendet, die keine ganzen Zahlen sind.

  3. Die Umwandlungscodes 'n' und 'N' stehen nur für die native Größe zur Verfügung (voreingestellt oder mit dem Bytereihenfolgezeichen '@' gewählt). Für die Standardgröße kannst du jenes der übrigen Formate für ganze Zahlen verwenden, das zu deiner Anwendung passt.

  4. Bei den Umwandlungscodes 'f', 'd' und 'e' verwendet die gepackte Darstellung das Format IEEE 754 binary32, binary64 beziehungsweise binary16 (für 'f', 'd' beziehungsweise 'e'), unabhängig vom Gleitkommaformat der Plattform.

  5. Der Typcode 'P' steht nur für die native Bytereihenfolge zur Verfügung (voreingestellt oder mit dem Bytereihenfolgezeichen '@' gewählt). Das Bytereihenfolgezeichen '=' wählt anhand des Hostsystems zwischen Little- und Big-Endian. Das Modul struct deutet das nicht als native Reihenfolge, daher steht das Format 'P' dort nicht zur Verfügung.

  6. Der Typ IEEE 754 binary16 („halbe Genauigkeit“) kam mit der Überarbeitung des IEEE-754-Standards von 2008 hinzu. Er hat ein Vorzeichenbit, einen 5-Bit-Exponenten und 11 Bit Genauigkeit (davon 10 Bit ausdrücklich gespeichert) und kann Zahlen zwischen etwa 6.1e-05 und 6.5e+04 mit voller Genauigkeit darstellen. Dieser Typ wird von C-Compilern nicht breit unterstützt: Er steht als Typ _Float16 zur Verfügung, wenn der Compiler den Anhang H des C23-Standards unterstützt. Auf einer typischen Maschine lässt sich ein unsigned short zum Speichern verwenden, nicht aber für Rechenoperationen. Näheres auf der Wikipedia-Seite zum Gleitkommaformat halber Genauigkeit.

  7. Beim Packen fügt 'x' ein NUL-Byte ein.

  8. Der Typcode 'p' kodiert eine „Pascal-Zeichenkette“, also eine kurze Zeichenkette veränderlicher Länge, die in einer festen Anzahl von Bytes gespeichert wird, die die Wiederholungszahl angibt. Das erste gespeicherte Byte ist die Länge der Zeichenkette oder 255, je welcher Wert kleiner ist. Danach folgen die Bytes der Zeichenkette. Ist die an pack() übergebene Bytefolge zu lang (länger als die Wiederholungszahl minus 1), werden nur die führenden count-1 Bytes der Zeichenkette gespeichert. Ist die Bytefolge kürzer als count-1, wird sie mit Nullbytes aufgefüllt, sodass insgesamt genau count Bytes verwendet werden. Beachte, dass der Typcode 'p' bei unpack() count Bytes verbraucht, das zurückgegebene bytes-Objekt aber nie mehr als 255 Bytes enthalten kann. Beim Packen werden Argumente der Typen bytes und bytearray angenommen.

  9. Beim Typcode 's' gilt die Zahl als Länge der Bytefolge und nicht als Wiederholungszahl wie bei den übrigen Typcodes; '10s' meint zum Beispiel eine einzelne 10 Byte lange Zeichenkette, die auf eine einzelne Python-Bytefolge abgebildet wird, während '10c' 10 einzelne Elemente von je einem Byte meint (also cccccccccc), die auf zehn verschiedene Python-bytes-Objekte abgebildet werden. (Unter Beispiele wird der Unterschied anschaulich gezeigt.) Ist keine Zahl angegeben, gilt 1. Beim Packen wird die Bytefolge passend abgeschnitten oder mit Nullbytes aufgefüllt. Beim Entpacken hat das entstehende bytes-Objekt stets genau die angegebene Anzahl von Bytes. Als Sonderfall meint '0s' eine einzelne, leere Bytefolge (während '0c' 0 Zeichen meint). Beim Packen werden Argumente der Typen bytes und bytearray angenommen.

  10. Bei den Typcodes 'Zf' und 'Zd' verwendet die gepackte Darstellung für die Bestandteile der komplexen Zahl das Format IEEE 754 binary32 beziehungsweise binary64, unabhängig vom Gleitkommaformat der Plattform. Beachte, dass komplexe Typen uneingeschränkt zur Verfügung stehen, obwohl sie in C ein optionales Merkmal sind. Wie im C11-Standard festgelegt, wird jeder komplexe Typ durch ein zweielementiges C-Array dargestellt, das den Real- und den Imaginärteil enthält. Die Formatzeichen 'F' und 'D' (für 'Zf' beziehungsweise 'Zd') werden aus Gründen der Kompatibilität weiter unterstützt.

Einem Typcode kann eine ganzzahlige Wiederholungszahl vorangestellt werden. Die Formatzeichenkette '4h' bedeutet zum Beispiel genau dasselbe wie 'hhhh'.

Leerraumzeichen zwischen Formaten werden übergangen. Eine Wiederholungszahl und ihr Format dürfen allerdings keinen Leerraum enthalten.

Wird ein Wert x mit einem der Formate für ganze Zahlen ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q') gepackt und liegt x außerhalb des für dieses Format gültigen Bereichs, wird struct.error ausgelöst.

Geändert in Version 3.1: Früher ließen einige der Formate für ganze Zahlen Werte außerhalb des Bereichs umlaufen und lösten DeprecationWarning statt von struct.error aus.

Beim Typcode '?' ist der Rückgabewert entweder True oder False. Beim Packen wird der Wahrheitswert des Argumentobjekts verwendet. Gepackt wird 0 oder 1 in der nativen oder standardisierten bool-Darstellung. Beim Entpacken ergibt jeder Wert außer null True.

Beispiele

Bemerkung

Beispiele mit nativer Bytereihenfolge (gekennzeichnet durch das Formatpräfix '@' oder durch das Fehlen eines Präfixzeichens) müssen nicht zu dem passen, was die Maschine des Lesers erzeugt, denn das hängt von Plattform und Compiler ab.

Ganze Zahlen dreier verschiedener Größen in Big-Endian-Reihenfolge packen und entpacken:

>>> from struct import *
>>> pack(">bhl", 1, 2, 3)
b'\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('>bhl', b'\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('>bhl')
7

Versuch, eine ganze Zahl zu packen, die für das festgelegte Feld zu groß ist:

>>> pack(">h", 99999)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
struct.error: 'h' format requires -32768 <= number <= 32767

Der Unterschied zwischen den Formatzeichen 's' und 'c':

>>> pack("@ccc", b'1', b'2', b'3')
b'123'
>>> pack("@3s", b'123')
b'123'

Entpackte Felder lassen sich benennen, indem man sie Variablen zuweist oder das Ergebnis in ein benanntes Tupel hüllt:

>>> record = b'raymond   \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)

>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)

Die Reihenfolge der Typcodes kann im nativen Modus die Größe beeinflussen, da Füllbytes implizit hinzukommen. Im Standardmodus liegt es beim Benutzer, gewünschte Füllbytes einzufügen. Beachte beim ersten pack-Aufruf unten, dass nach dem gepackten '#' drei NUL-Bytes hinzukamen, um die folgende ganze Zahl an einer Vier-Byte-Grenze auszurichten. Die Ausgabe in diesem Beispiel entstand auf einer Little-Endian-Maschine:

>>> pack('@ci', b'#', 0x12131415)
b'#\x00\x00\x00\x15\x14\x13\x12'
>>> pack('@ic', 0x12131415, b'#')
b'\x15\x14\x13\x12#'
>>> calcsize('@ci')
8
>>> calcsize('@ic')
5

Beim folgenden Format 'llh0l' kommen am Ende zwei Füllbytes hinzu, sofern die longs der Plattform an Vier-Byte-Grenzen ausgerichtet sind:

>>> pack('@llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

Siehe auch

Modul array

Gepackte binäre Ablage gleichartiger Daten.

Modul json

JSON-Kodierer und -Dekodierer.

Modul pickle

Serialisierung von Python-Objekten.

Anwendungsfälle

Für das Modul struct gibt es zwei Hauptanwendungsfälle: den Datenaustausch zwischen Python- und C-Code innerhalb einer Anwendung oder mit einer anderen Anwendung, die mit demselben Compiler gebaut wurde (native Formate), und den Datenaustausch zwischen Anwendungen mit vereinbarter Datenanordnung (Standardformate). Im Allgemeinen unterscheiden sich die Formatzeichenketten für diese beiden Bereiche.

Native Formate

Baut man Formatzeichenketten, die native Anordnungen nachbilden, legen Compiler und Maschinenarchitektur Bytereihenfolge und Füllbytes fest. In solchen Fällen sollte das Formatzeichen @ verwendet werden, um native Bytereihenfolge und Datengrößen anzugeben. Innere Füllbytes werden normalerweise selbsttätig eingefügt. Möglicherweise ist am Ende einer Formatzeichenkette ein Typcode mit Wiederholungszahl null nötig, um auf die richtige Bytegrenze aufzurunden und aufeinanderfolgende Datenstücke korrekt auszurichten.

Betrachte diese zwei einfachen Beispiele (auf einer 64-Bit-Maschine mit Little-Endian):

>>> calcsize('@lhl')
24
>>> calcsize('@llh')
18

Ohne zusätzliche Füllbytes werden die Daten am Ende der zweiten Formatzeichenkette nicht auf eine Acht-Byte-Grenze aufgefüllt. Ein Formatcode mit Wiederholungszahl null löst das Problem:

>>> calcsize('@llh0l')
24

Der Typcode 'x' kann die Wiederholung angeben, bei nativen Formaten ist aber ein Format mit Wiederholungszahl null wie '0l' die bessere Wahl.

Voreingestellt werden native Bytereihenfolge und Ausrichtung verwendet. Besser ist es aber, das ausdrücklich zu sagen und das Präfixzeichen '@' zu verwenden.

Standardformate

Werden Daten über den eigenen Prozess hinaus ausgetauscht, etwa über ein Netzwerk oder einen Speicher, sei genau: Gib Bytereihenfolge, Größe und Ausrichtung ausdrücklich an. Verlasse dich nicht darauf, dass sie zur nativen Reihenfolge einer bestimmten Maschine passen. Die Bytereihenfolge im Netzwerk ist zum Beispiel Big-Endian, während viele verbreitete CPUs Little-Endian sind. Legt man das ausdrücklich fest, muss sich der Benutzer nicht um die Besonderheiten der Plattform kümmern, auf der sein Code läuft. Das erste Zeichen sollte in der Regel < oder > (oder !) sein. Für Füllbytes ist der Programmierer zuständig. Das Formatzeichen mit Wiederholungszahl null funktioniert hier nicht. Stattdessen muss der Benutzer ausdrücklich Füllbytes 'x' einfügen, wo sie nötig sind. Die Beispiele aus dem vorigen Abschnitt sehen dann so aus:

>>> calcsize('<qh6xq')
24
>>> pack('<qh6xq', 1, 2, 3) == pack('@lhl', 1, 2, 3)
True
>>> calcsize('@llh')
18
>>> pack('@llh', 1, 2, 3) == pack('<qqh', 1, 2, 3)
True
>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
24
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
True

Für die obigen Ergebnisse (ausgeführt auf einer 64-Bit-Maschine) ist nicht garantiert, dass sie auf anderen Maschinen genauso ausfallen. Die folgenden Beispiele liefen zum Beispiel auf einer 32-Bit-Maschine:

>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
12
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
False

Klassen

Das Modul struct definiert außerdem den folgenden Typ:

class struct.Struct(format)

Gibt ein neues Struct-Objekt zurück, das Binärdaten gemäß der Formatzeichenkette format schreibt und liest. Ein Struct-Objekt einmal zu erzeugen und seine Methoden aufzurufen ist effizienter, als Funktionen auf Modulebene mit demselben Format aufzurufen, da die Formatzeichenkette nur einmal kompiliert wird.

Bemerkung

Die kompilierten Fassungen der zuletzt an die Funktionen auf Modulebene übergebenen Formatzeichenketten werden zwischengespeichert. Programme, die nur wenige Formatzeichenketten verwenden, müssen sich daher nicht darum kümmern, eine einzelne Struct-Instanz wiederzuverwenden.

Kompilierte Struct-Objekte unterstützen die folgenden Methoden und Attribute:

pack(v1, v2, ...)

Gleichbedeutend mit der Funktion pack(), mit dem kompilierten Format. (len(result) entspricht size.)

pack_into(buffer, offset, v1, v2, ...)

Gleichbedeutend mit der Funktion pack_into(), mit dem kompilierten Format.

unpack(buffer)

Gleichbedeutend mit der Funktion unpack(), mit dem kompilierten Format. Die Größe des Puffers in Bytes muss size entsprechen.

unpack_from(buffer, offset=0)

Gleichbedeutend mit der Funktion unpack_from(), mit dem kompilierten Format. Die Größe des Puffers in Bytes ab der Position offset muss mindestens size sein.

iter_unpack(buffer)

Gleichbedeutend mit der Funktion iter_unpack(), mit dem kompilierten Format. Die Größe des Puffers in Bytes muss ein Vielfaches von size sein.

Added in version 3.4.

format

Die Formatzeichenkette, mit der dieses Struct-Objekt erzeugt wurde.

Geändert in Version 3.7: Der Typ der Formatzeichenkette ist jetzt str statt von bytes.

size

Die berechnete Größe des Structs (und damit des von der Methode pack() erzeugten bytes-Objekts), die zu format gehört.

Geändert in Version 3.13: Die Ausgabe von repr() für Structs hat sich geändert. Sie lautet jetzt:

>>> Struct('i')
Struct('i')