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¶
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,
0am Ende des Streams oderNone, 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 negativenerrno-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
bytesfür binäre Streams undstrfü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/strzurück.
- readlines() list¶
Liest bis zum Ende des Streams und gibt eine
listvon 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
OSErroraus (oderValueErrorbei 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östOSErroraus, wenn der Stream nicht positionierbar ist.
- 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, sodasswith 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_objundmp_stream_write1_objbereit, 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 wiemachine.UARTverwendet, um deren eigeneread/writezu implementieren – aber keine standardmäßige Stream-Klasse bindet sie als von Python aufrufbareread1/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.
- close() None¶
Schließt den Stream und gibt den zugrunde liegenden Puffer frei. Weitere Operationen auf einem geschlossenen Stream lösen
ValueErroraus.
- 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.
- 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
ValueErroraus.
- 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.
- close() None¶
Schließt den Stream und gibt den zugrunde liegenden Puffer frei. Weitere Operationen auf einem geschlossenen Stream lösen
ValueErroraus.
- 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
ValueErroraus.
- getvalue() bytes
Gibt den aktuellen Inhalt des zugrunde liegenden Puffers zurück.