Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 358 – Das „bytes“-Objekt

Autor:
Neil Schemenauer <nas at arctrix.com>, Guido van Rossum <guido at python.org>
Status:
Final
Typ:
Standards Track
Erstellt:
15. Feb. 2006
Python-Version:
2.6, 3.0
Post-History:


Inhaltsverzeichnis

Update

Dieser PEP wurde teilweise durch PEP 3137 abgelöst.

Zusammenfassung

Dieser PEP beschreibt die Einführung eines rohen Byte-Sequenztyps. Die Ergänzung des bytes-Typs ist ein Schritt im Übergang zu Unicode-basierten str-Objekten, die in Python 3.0 eingeführt werden.

Der PEP beschreibt, wie der bytes-Typ in Python 2.6 und in Python 3.0 funktionieren soll. (Gelegentlich gibt es Unterschiede, da in Python 2.6 zwei String-Typen existieren, str und unicode, während in Python 3.0 nur ein String-Typ vorhanden sein wird, dessen Name str lauten wird, dessen Semantik aber der des 2.6 unicode-Typs entspricht.)

Motivation

Die aktuellen String-Objekte von Python sind überladen. Sie dienen sowohl zur Speicherung von Zeichensequenzen als auch von Byte-Sequenzen. Diese Überladung des Zwecks führt zu Verwirrung und Fehlern. In zukünftigen Versionen von Python werden String-Objekte zur Speicherung von Zeichendaten verwendet. Das bytes-Objekt wird die Rolle eines Byte-Containers übernehmen. Schließlich wird der unicode-Typ in str umbenannt und der alte str-Typ wird entfernt.

Spezifikation

Ein bytes-Objekt speichert eine veränderliche Sequenz von ganzen Zahlen im Bereich von 0 bis 255. Im Gegensatz zu String-Objekten gibt die Indizierung eines bytes-Objekts eine ganze Zahl zurück. Das Zuweisen oder Vergleichen eines anderen Objekts als einer ganzen Zahl zu einem Element verursacht eine Ausnahme vom Typ TypeError. Das Zuweisen eines Elements mit einem Wert außerhalb des Bereichs von 0 bis 255 verursacht eine Ausnahme vom Typ ValueError. Die Methode .__len__() von bytes gibt die Anzahl der gespeicherten ganzen Zahlen zurück (d.h. die Anzahl der Bytes).

Der Konstruktor des bytes-Objekts hat die folgende Signatur

bytes([initializer[, encoding]])

Wenn keine Argumente übergeben werden, wird ein bytes-Objekt mit null Elementen erstellt und zurückgegeben. Das Initialisierungsargument kann ein String sein (in 2.6 entweder str oder unicode), ein Iterable von ganzen Zahlen oder eine einzelne ganze Zahl. Der Pseudocode für den Konstruktor (optimiert auf klare Semantik, nicht auf Geschwindigkeit) lautet:

def bytes(initializer=0, encoding=None):
    if isinstance(initializer, int): # In 2.6, int -> (int, long)
        initializer = [0]*initializer
    elif isinstance(initializer, basestring):
        if isinstance(initializer, unicode): # In 3.0, "if True"
            if encoding is None:
                # In 3.0, raise TypeError("explicit encoding required")
                encoding = sys.getdefaultencoding()
            initializer = initializer.encode(encoding)
        initializer = [ord(c) for c in initializer]
    else:
        if encoding is not None:
            raise TypeError("no encoding allowed for this initializer")
        tmp = []
        for c in initializer:
            if not isinstance(c, int):
                raise TypeError("initializer must be iterable of ints")
            if not 0 <= c < 256:
                raise ValueError("initializer element out of range")
            tmp.append(c)
        initializer = tmp
    new = <new bytes object of length len(initializer)>
    for i, c in enumerate(initializer):
        new[i] = c
    return new

Die Methode .__repr__() gibt einen String zurück, der ausgewertet werden kann, um ein neues bytes-Objekt mit einem Byte-Literal zu erzeugen.

>>> bytes([10, 20, 30])
b'\n\x14\x1e'

Das Objekt verfügt über eine Methode .decode(), die der Methode .decode() des str-Objekts entspricht. Das Objekt verfügt über eine Klassenmethode .fromhex(), die einen String von Zeichen aus der Menge [0-9a-fA-F ] entgegennimmt und ein bytes-Objekt zurückgibt (ähnlich wie binascii.unhexlify). Zum Beispiel:

>>> bytes.fromhex('5c5350ff')
b'\\SP\xff'
>>> bytes.fromhex('5c 53 50 ff')
b'\\SP\xff'

Das Objekt verfügt über eine Methode .hex(), die die umgekehrte Konvertierung durchführt (ähnlich wie binascii.hexlify).

>> bytes([92, 83, 80, 255]).hex()
'5c5350ff'

Das bytes-Objekt hat einige Methoden, die den List-Methoden und andere, die den String-Methoden ähneln. Hier ist eine vollständige Liste der Methoden mit ihren ungefähren Signaturen:

.__add__(bytes) -> bytes
.__contains__(int | bytes) -> bool
.__delitem__(int | slice) -> None
.__delslice__(int, int) -> None
.__eq__(bytes) -> bool
.__ge__(bytes) -> bool
.__getitem__(int | slice) -> int | bytes
.__getslice__(int, int) -> bytes
.__gt__(bytes) -> bool
.__iadd__(bytes) -> bytes
.__imul__(int) -> bytes
.__iter__() -> iterator
.__le__(bytes) -> bool
.__len__() -> int
.__lt__(bytes) -> bool
.__mul__(int) -> bytes
.__ne__(bytes) -> bool
.__reduce__(...) -> ...
.__reduce_ex__(...) -> ...
.__repr__() -> str
.__reversed__() -> bytes
.__rmul__(int) -> bytes
.__setitem__(int | slice, int | iterable[int]) -> None
.__setslice__(int, int, iterable[int]) -> Bote
.append(int) -> None
.count(int) -> int
.decode(str) -> str | unicode # in 3.0, only str
.endswith(bytes) -> bool
.extend(iterable[int]) -> None
.find(bytes) -> int
.index(bytes | int) -> int
.insert(int, int) -> None
.join(iterable[bytes]) -> bytes
.partition(bytes) -> (bytes, bytes, bytes)
.pop([int]) -> int
.remove(int) -> None
.replace(bytes, bytes) -> bytes
.rindex(bytes | int) -> int
.rpartition(bytes) -> (bytes, bytes, bytes)
.split(bytes) -> list[bytes]
.startswith(bytes) -> bool
.reverse() -> None
.rfind(bytes) -> int
.rindex(bytes | int) -> int
.rsplit(bytes) -> list[bytes]
.translate(bytes, [bytes]) -> bytes

Beachten Sie das auffällige Fehlen von .isupper(), .upper() und verwandten Methoden. (Siehe jedoch „Offene Fragen“ unten.) Es gibt kein .__hash__(), da das Objekt veränderlich ist. Es gibt keinen Anwendungsfall für eine .sort()-Methode.

Der bytes-Typ unterstützt auch die Puffer-Schnittstelle, die das Lesen und Schreiben von binären (aber nicht zeichenbasierten) Daten unterstützt.

Themen außerhalb des Geltungsbereichs

  • Python 3k wird ein ganz anderes E/A-Subsystem haben. Die Entscheidung, wie dieses E/A-Subsystem funktionieren und mit dem bytes-Objekt interagieren soll, liegt außerhalb des Geltungsbereichs dieses PEP. Es wird jedoch erwartet, dass die binäre E/A Bytes liest und schreibt, während die Text-E/A Strings liest. Da der bytes-Typ die Puffer-Schnittstelle unterstützt, werden die bestehenden binären E/A-Operationen in Python 2.6 bytes-Objekte unterstützen.
  • Es wurde vorgeschlagen, eine spezielle Methode namens .__bytes__() in die Sprache aufzunehmen, um Objekten die Konvertierung in Byte-Arrays zu ermöglichen. Diese Entscheidung liegt außerhalb des Geltungsbereichs.
  • Ein Byte-Literal der Form b"..." wird ebenfalls vorgeschlagen. Dies ist Gegenstand von PEP 3112.

Offene Fragen

  • Die Methode .decode() ist redundant, da ein bytes-Objekt b auch durch Aufruf von unicode(b, <encoding>) (in 2.6) oder str(b, <encoding>) (in 3.0) dekodiert werden kann. Benötigen wir überhaupt encode/decode-Methoden? In gewisser Weise ist die Schreibweise über einen Konstruktor sauberer.
  • Die Methoden müssen noch sorgfältiger spezifiziert werden.
  • Unterstützung für Pickling und Marshalling muss spezifiziert werden.
  • Sollen all diese Listenmethoden wirklich implementiert werden?
  • Man könnte argumentieren, dass .ljust(), .rjust(), .center() mit einem obligatorischen zweiten Argument unterstützt werden sollten.
  • Man könnte argumentieren, dass .split() mit einem obligatorischen Argument unterstützt werden sollte.
  • Man könnte sogar argumentieren, dass .islower(), .isupper(), .isspace(), .isalpha(), .isalnum(), .isdigit() und die entsprechenden Konvertierungen (.lower() etc.) unterstützt werden sollten, wobei die ASCII-Definitionen für Buchstaben, Ziffern und Leerzeichen verwendet werden. Wenn dies akzeptiert wird, werden die Argumente für .ljust(), .rjust(), .center() und .split() viel stärker, und sie sollten auch Standardargumente haben, die ein ASCII-Leerzeichen oder alle ASCII-Leerzeichen (für .split()) verwenden.

Häufig gestellte Fragen

F: Warum gibt es das optionale Encoding-Argument, wenn die encode-Methode von Unicode-Objekten dasselbe tut?

A: In der aktuellen Version von Python gibt die encode-Methode ein str-Objekt zurück, und wir können das nicht ändern, ohne Code zu brechen. Die Konstruktion bytes(s.encode(...)) ist teuer, da die Byte-Sequenz mehrfach kopiert werden muss. Außerdem bietet Python im Allgemeinen zwei Möglichkeiten, ein Objekt vom Typ A in ein Objekt vom Typ B zu konvertieren: Fordern Sie eine A-Instanz auf, sich selbst in ein B zu konvertieren, oder bitten Sie den Typ B, eine neue Instanz aus einem A zu erstellen. Abhängig davon, was A und B sind, sind beide APIs sinnvoll; manchmal erfordern Gründe der Entkopplung, dass A nichts über B wissen kann, in diesem Fall müssen Sie den letzteren Ansatz verwenden; manchmal kann B nichts über A wissen, in diesem Fall müssen Sie den ersteren verwenden.

F: Warum ignoriert bytes das Encoding-Argument, wenn der Initialisierer ein str ist? (Dies gilt nur für 2.6.)

A: In diesem Fall gibt es keine sinnvolle Bedeutung für das Encoding. str-Objekte *sind* Byte-Arrays und sie wissen nichts über die Kodierung der von ihnen enthaltenen Zeichendaten. Wir müssen davon ausgehen, dass der Programmierer ein str-Objekt bereitgestellt hat, das bereits die gewünschte Kodierung verwendet. Wenn Sie etwas anderes als eine reine Kopie der Bytes benötigen, müssen Sie den String zuerst dekodieren. Zum Beispiel:

bytes(s.decode(encoding1), encoding2)

F: Warum nicht das Encoding-Argument standardmäßig auf Latin-1 (oder eine andere Kodierung, die den gesamten Byte-Bereich abdeckt) anstelle von ASCII setzen?

A: Die systemweite Standardkodierung für Python ist ASCII. Es scheint am wenigsten verwirrend zu sein, diesen Standard zu verwenden. Außerdem ist in Py3k die Verwendung von Latin-1 als Standard möglicherweise nicht das, was die Benutzer erwarten. Zum Beispiel könnten sie eine Unicode-Kodierung bevorzugen. Jede Standardeinstellung wird nicht immer wie erwartet funktionieren. Zumindest wird ASCII laut protestieren, wenn Sie versuchen, Nicht-ASCII-Daten zu kodieren.


Quelle: https://github.com/python/peps/blob/main/peps/pep-0358.rst

Zuletzt geändert: 2025-02-01 08:59:27 GMT