io — Ein- und Ausgabeströme

Dieses Modul enthält zusätzliche Typen von stream-Objekten (dateiartigen Objekten) sowie Hilfsfunktionen. Es stellt die eingebaute Funktion open() bereit sowie textuelle und binäre Puffer im Arbeitsspeicher (StringIO, BytesIO), die die standardmäßige read/write/seek-Stream-Schnittstelle implementieren.

Konzeptionelle Hierarchie

Unterschied zu CPython

Die konzeptionelle Hierarchie der Stream-Basisklassen ist in MicroPython vereinfacht, wie in diesem Abschnitt beschrieben.

(Abstrakte) Stream-Basisklassen, die als Grundlage für das Verhalten aller konkreten Klassen dienen, halten sich in CPython an einige Dichotomien (paarweise Klassifizierungen). In MicroPython sind sie etwas vereinfacht und implizit gemacht, um höhere Effizienz zu erreichen und Ressourcen zu sparen.

Eine wichtige Dichotomie in CPython ist die zwischen gepufferten und ungepufferten Streams. In MicroPython sind derzeit alle Streams ungepuffert. Das liegt daran, dass alle modernen Betriebssysteme und sogar viele RTOSes und Dateisystemtreiber bereits auf ihrer Seite puffern. Eine weitere Pufferungsschicht hinzuzufügen ist kontraproduktiv (ein als „Bufferbloat“ bekanntes Problem) und verbraucht wertvollen Speicher. Beachten Sie, dass es dennoch Fälle gibt, in denen Pufferung nützlich sein kann, sodass wir zu einem späteren Zeitpunkt optionale Pufferungsunterstützung einführen könnten.

In CPython ist jedoch eine weitere wichtige Dichotomie mit der „Pufferung“ verknüpft: nämlich, ob ein Stream kurze Lese-/Schreibvorgänge zulassen kann oder nicht. Ein kurzer Lesevorgang liegt vor, wenn ein Benutzer z. B. 10 Bytes von einem Stream anfordert, aber weniger erhält; Entsprechendes gilt für Schreibvorgänge. In CPython sind ungepufferte Streams automatisch anfällig für kurze Operationen, während gepufferte Streams dagegen abgesichert sind. Das Fehlen kurzer Lese-/Schreibvorgänge ist ein wichtiges Merkmal, da es die Entwicklung prägnanterer und effizienterer Programme ermöglicht – etwas, das für MicroPython höchst wünschenswert ist. Obwohl MicroPython also keine gepufferten Streams unterstützt, bietet es dennoch Streams ohne kurze Operationen. Ob es kurze Operationen geben wird oder nicht, hängt von den Anforderungen jeder einzelnen Klasse ab, aber Entwicklern wird aus den oben genannten Gründen dringend empfohlen, das Verhalten ohne kurze Operationen zu bevorzugen. Beispielsweise ist bei MicroPython-Sockets garantiert, dass keine kurzen Lese-/Schreibvorgänge auftreten. Tatsächlich gibt es derzeit kein Beispiel für eine Stream-Klasse mit kurzen Operationen im Kern, und eine solche Klasse wäre spezifisch für bestimmte Hardware.

Das Verhalten ohne kurze Operationen wird bei nicht-blockierenden Streams knifflig, wobei blockierendes vs. nicht-blockierendes Verhalten eine weitere CPython-Dichotomie ist, die von MicroPython vollständig unterstützt wird. Nicht-blockierende Streams warten niemals darauf, dass Daten eintreffen oder geschrieben werden – sie lesen/schreiben, was immer möglich ist, oder signalisieren das Fehlen von Daten (oder die fehlende Möglichkeit, Daten zu schreiben). Dies steht offensichtlich im Widerspruch zur Richtlinie „keine kurzen Operationen“, und tatsächlich ist der Fall nicht-blockierender, gepufferter (und damit kurzoperationsfreier) Streams in CPython verworren – an manchen Stellen ist eine solche Kombination verboten, an anderen undefiniert oder einfach nicht dokumentiert, in manchen Fällen löst sie ausführliche Ausnahmen aus. In MicroPython ist die Sache viel einfacher: Nicht-blockierende Streams sind für effiziente asynchrone Operationen wichtig, daher hat diese Eigenschaft Vorrang vor der Eigenschaft „keine kurzen Operationen“. Während also blockierende Streams kurze Lese-/Schreibvorgänge nach Möglichkeit vermeiden (der einzige Fall, in dem ein kurzer Lesevorgang auftritt, ist das Erreichen des Dateiendes oder ein Fehler (aber Fehler liefern keine kurzen Daten zurück, sondern lösen Ausnahmen aus)), können nicht-blockierende Streams kurze Daten erzeugen, um eine Blockierung der Operation zu vermeiden.

Die letzte Dichotomie ist die zwischen binären und textuellen Streams. MicroPython unterstützt diese natürlich, aber während Text-Streams in CPython von Natur aus gepuffert sind, sind sie es in MicroPython nicht. (Dies ist in der Tat einer der Fälle, für die wir Pufferungsunterstützung einführen könnten.)

Beachten Sie, dass MicroPython aus Effizienzgründen keine abstrakten Basisklassen entsprechend der oben genannten Hierarchie bereitstellt, und es ist nicht möglich, eine Stream-Klasse in reinem Python zu implementieren oder davon abzuleiten.

Funktionen

io.open(name: str, mode: str = 'r', **kwargs) Any

Öffnet eine Datei. Die eingebaute Funktion open() ist ein Alias für diese Funktion. Der Parameter mode wird immer unterstützt; die Unterstützung anderer Argumente kann variieren.

Klassen

class io.IOBase

Basisklasse für Stream-Objekte („dateiartige“ Objekte). Konkrete Unterklassen implementieren die unten aufgeführten Low-Level-I/O-Methoden (readinto, write, ioctl); die Laufzeitumgebung baut darauf das übergeordnete Stream-Protokoll auf (read, readline, readlines, close, Iteration), sodass jede Stream-Instanz diese Methoden unterstützt, selbst wenn die Unterklasse sie nicht definiert.

Implementierungsmethoden (überschreiben Sie diese in einer Unterklasse):

readinto(buf: bytearray) int | None

Liest Bytes in den beschreibbaren Puffer buf. Gibt die Anzahl der gelesenen Bytes zurück, 0 am Ende des Streams oder None, wenn derzeit keine Daten verfügbar sind (bei einem nicht-blockierenden Stream).

write(buf: bytes) int | None

Schreibt die Bytes in buf. Gibt die Anzahl der geschriebenen Bytes zurück oder None, wenn der Schreibvorgang derzeit nicht ausgeführt werden kann (bei einem nicht-blockierenden Stream).

ioctl(request: int, arg: int) int

Steuert den zugrunde liegenden Stream bzw. das Gerät. request ist einer der MP_STREAM_*-Anforderungscodes. Gibt bei Erfolg einen nicht-negativen Wert zurück oder bei einem Fehler einen negativen errno-Wert.

Stream-Protokollmethoden (verfügbar bei jeder Stream-Instanz):

read(size: int = -1)

Liest bis zu size Bytes (oder Zeichen im Textmodus) und gibt sie zurück. Wird size weggelassen oder ist negativ, wird bis zum Ende des Streams gelesen. Gibt bytes für binäre Streams und str für textuelle Streams zurück; ein leeres Ergebnis zeigt das Ende des Streams an.

readline(size: int = -1)

Liest eine Zeile, einschließlich des abschließenden Zeilenumbruchs, falls vorhanden, und gibt sie zurück. Wird size angegeben, werden höchstens size Bytes (oder Zeichen) gelesen. Gibt am Ende des Streams ein leeres bytes / str zurück.

readlines() list

Liest bis zum Ende des Streams und gibt eine list von Zeilen zurück, jede mit ihrem abschließenden Zeilenumbruch.

close() None

Schließt den Stream und gibt alle zugrunde liegenden Ressourcen frei. Operationen auf einem geschlossenen Stream lösen OSError aus (oder ValueError bei Streams im Arbeitsspeicher).

seek(offset: int, whence: int = 0) int

Ändert die aktuelle Stream-Position auf offset Bytes relativ zu whence (0 = Anfang des Streams, 1 = aktuelle Position, 2 = Ende des Streams). Gibt die neue absolute Position zurück. Löst OSError aus, wenn der Stream nicht positionierbar ist.

tell() int

Gibt die aktuelle absolute Position im Stream zurück. Entspricht seek(0, 1).

flush() None

Leert alle Schreibpuffer und schiebt ausstehende Daten an das zugrunde liegende Gerät oder die Datei. Bei Streams, die nicht puffern, ohne Wirkung.

Das direkte Iterieren über einen Stream liefert bei jeder Iteration eine Zeile – entspricht dem Aufruf von readline() in einer Schleife, bis die leere Zeile als Stream-Ende-Markierung zurückgegeben wird. Ein Stream unterstützt außerdem das Kontextmanager-Protokoll, sodass with open(...) as f: den Stream automatisch schließt.

Bemerkung

Das Stream-Modul von MicroPython stellt außerdem die mit „1“ endenden C-Hilfsfunktionen mp_stream_read1_obj, mp_stream_readinto1_obj und mp_stream_write1_obj bereit, die einen einzelnen zugrunde liegenden I/O-Aufruf ausführen, anstatt zu schleifen, bis die Anforderung vollständig erfüllt ist. Sie werden intern von Klassen wie machine.UART verwendet, um deren eigene read / write zu implementieren – aber keine standardmäßige Stream-Klasse bindet sie als von Python aufrufbare read1 / readinto1 / write1-Methoden ein.

class io.StringIO(string: str = '')

Dateiartiges Objekt im Arbeitsspeicher für Ein-/Ausgabe im Textmodus (ähnlich einer normalen Datei, die mit dem Modifikator „t“ geöffnet wurde). Der Anfangsinhalt kann mit dem Parameter string angegeben werden (der eine normale Zeichenkette sein sollte). Instanzen unterstützen außerdem das Kontextmanager-Protokoll (verwendbar in einer with-Anweisung).

read(size: int = -1) str

Liest bis zu size Zeichen und gibt sie zurück. Wird size weggelassen oder ist negativ, wird der gesamte verbleibende Inhalt gelesen und zurückgegeben.

readline(size: int = -1) str

Liest eine Zeile und gibt sie zurück. Wird size angegeben, werden höchstens size Zeichen gelesen.

readinto(buf: bytearray) int

Liest in den vorab zugewiesenen, beschreibbaren Puffer buf und gibt die Anzahl der gelesenen Bytes zurück.

write(s: str) int

Schreibt die Zeichenkette s und gibt die Anzahl der geschriebenen Zeichen zurück.

seek(offset: int, whence: int = 0) int

Ändert die Stream-Position auf offset relativ zu whence (0 = Anfang, 1 = aktuell, 2 = Ende) und gibt die neue absolute Position zurück.

tell() int

Gibt die aktuelle Stream-Position zurück.

flush() None

Leert die Schreibpuffer. Bei einem Stream im Arbeitsspeicher ohne Wirkung.

close() None

Schließt den Stream und gibt den zugrunde liegenden Puffer frei. Weitere Operationen auf einem geschlossenen Stream lösen ValueError aus.

getvalue() str

Gibt den aktuellen Inhalt des zugrunde liegenden Puffers zurück.

class io.StringIO(alloc_size: int)

Erstellt ein leeres StringIO-Objekt, das vorab zugewiesen ist, um bis zu alloc_size Bytes aufzunehmen, sodass das Schreiben von bis zu so vielen Bytes den Puffer nicht neu zuweist (was eine Out-of-Memory-Situation oder Speicherfragmentierung vermeidet). Dieser Konstruktor ist eine MicroPython-Erweiterung, die nur für Sonderfälle und systemnahe Bibliotheken empfohlen wird, nicht für Endbenutzeranwendungen.

Unterschied zu CPython

Dieser Konstruktor ist eine MicroPython-Erweiterung.

read(size: int = -1) str

Liest bis zu size Zeichen und gibt sie zurück. Wird size weggelassen oder ist negativ, wird der gesamte verbleibende Inhalt gelesen und zurückgegeben.

readline(size: int = -1) str

Liest eine Zeile und gibt sie zurück. Wird size angegeben, werden höchstens size Zeichen gelesen.

readinto(buf: bytearray) int

Liest in den vorab zugewiesenen, beschreibbaren Puffer buf und gibt die Anzahl der gelesenen Bytes zurück.

write(s: str) int

Schreibt die Zeichenkette s und gibt die Anzahl der geschriebenen Zeichen zurück.

seek(offset: int, whence: int = 0) int

Ändert die Stream-Position auf offset relativ zu whence (0 = Anfang, 1 = aktuell, 2 = Ende) und gibt die neue absolute Position zurück.

tell() int

Gibt die aktuelle Stream-Position zurück.

flush() None

Leert die Schreibpuffer. Bei einem Stream im Arbeitsspeicher ohne Wirkung.

close() None

Schließt den Stream und gibt den zugrunde liegenden Puffer frei. Weitere Operationen auf einem geschlossenen Stream lösen ValueError aus.

getvalue() str

Gibt den aktuellen Inhalt des zugrunde liegenden Puffers zurück.

class io.BytesIO(string: bytes = b'')

Dateiartiges Objekt im Arbeitsspeicher für Ein-/Ausgabe im Binärmodus (ähnlich einer normalen Datei, die mit dem Modifikator „b“ geöffnet wurde). Der Anfangsinhalt kann mit dem Parameter string angegeben werden (der ein Bytes-Objekt sein sollte). Instanzen unterstützen außerdem das Kontextmanager-Protokoll (verwendbar in einer with-Anweisung).

read(size: int = -1) bytes

Liest bis zu size Bytes und gibt sie zurück. Wird size weggelassen oder ist negativ, wird der gesamte verbleibende Inhalt gelesen und zurückgegeben.

readline(size: int = -1) bytes

Liest eine Zeile und gibt sie zurück. Wird size angegeben, werden höchstens size Bytes gelesen.

readinto(buf: bytearray) int

Liest in den vorab zugewiesenen, beschreibbaren Puffer buf und gibt die Anzahl der gelesenen Bytes zurück.

write(b: bytes) int

Schreibt das bytesartige Objekt b und gibt die Anzahl der geschriebenen Bytes zurück.

seek(offset: int, whence: int = 0) int

Ändert die Stream-Position auf offset relativ zu whence (0 = Anfang, 1 = aktuell, 2 = Ende) und gibt die neue absolute Position zurück.

tell() int

Gibt die aktuelle Stream-Position zurück.

flush() None

Leert die Schreibpuffer. Bei einem Stream im Arbeitsspeicher ohne Wirkung.

close() None

Schließt den Stream und gibt den zugrunde liegenden Puffer frei. Weitere Operationen auf einem geschlossenen Stream lösen ValueError aus.

getvalue() bytes

Gibt den aktuellen Inhalt des zugrunde liegenden Puffers zurück.

class io.BytesIO(alloc_size: int)

Erstellt ein leeres BytesIO-Objekt, das vorab zugewiesen ist, um bis zu alloc_size Bytes aufzunehmen, sodass das Schreiben von bis zu so vielen Bytes den Puffer nicht neu zuweist (was eine Out-of-Memory-Situation oder Speicherfragmentierung vermeidet). Dieser Konstruktor ist eine MicroPython-Erweiterung, die nur für Sonderfälle und systemnahe Bibliotheken empfohlen wird, nicht für Endbenutzeranwendungen.

Unterschied zu CPython

Dieser Konstruktor ist eine MicroPython-Erweiterung.

read(size: int = -1) bytes

Liest bis zu size Bytes und gibt sie zurück. Wird size weggelassen oder ist negativ, wird der gesamte verbleibende Inhalt gelesen und zurückgegeben.

readline(size: int = -1) bytes

Liest eine Zeile und gibt sie zurück. Wird size angegeben, werden höchstens size Bytes gelesen.

readinto(buf: bytearray) int

Liest in den vorab zugewiesenen, beschreibbaren Puffer buf und gibt die Anzahl der gelesenen Bytes zurück.

write(b: bytes) int

Schreibt das bytesartige Objekt b und gibt die Anzahl der geschriebenen Bytes zurück.

seek(offset: int, whence: int = 0) int

Ändert die Stream-Position auf offset relativ zu whence (0 = Anfang, 1 = aktuell, 2 = Ende) und gibt die neue absolute Position zurück.

tell() int

Gibt die aktuelle Stream-Position zurück.

flush() None

Leert die Schreibpuffer. Bei einem Stream im Arbeitsspeicher ohne Wirkung.

close() None

Schließt den Stream und gibt den zugrunde liegenden Puffer frei. Weitere Operationen auf einem geschlossenen Stream lösen ValueError aus.

getvalue() bytes

Gibt den aktuellen Inhalt des zugrunde liegenden Puffers zurück.