Python 2 -> 3: Ersatz für array module bei Binärdaten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Thomas_W123
User
Beiträge: 8
Registriert: Freitag 23. Juli 2010, 16:49

Hallo,
ich würde gerne (bzw. muss) ein Modul für ein Netzwerkprotokoll welches für Python 2 geschrieben wurde, mit Python 3 verwenden.
Die einfachen Dinge erledigt das 2to3 Skript. Das Hauptproblem ist allerdings, dass an unendlich vielen Stellen das array modul mit "packet = array.array('c')" verwendet wird. Es werden viele Strings oder auch andere Daten in ein Array gewandelt, die dann letztenendes übers Netzwerk auf die Reise gehen. Aufgrund der tiefgreifenden Änderung bei der Ablage von Strings bei Python 3 ist das nicht mehr kompatibel.

Darum meine Frage, ob es irgendwo einen gleichwertigen Ersatz für das array Modul gibt, das die gleiche Funktionalität unter Python 3 wie unter Python 2 zur Verfügung stellt.

Ich habe testweise probiert die arrays durch ein bytearray() zu ersetzen, aber wenn ich dort Daten mit extend() anhängen will, muss ich den Typ des Parameters prüfen. Ist es ein String dann das encoding angeben, bei anderen Typen etwas anderes usw., es ist auf jeden Fall nicht ganz so einfach da ich jede Stelle einzeln anfassen müsste. Das Array Modul unter Python 2 scheint das alles automatisch gemacht zu haben.

Vielleicht hat ja einer einen heißen Tipp. Danke schonmal
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@Thomas_W123: dass Python2 nicht sauber zwischen Bytes und Strings unterscheidet, mußt Du jetzt bei Python3 eben ausbaden. Ein bytearray ist für Dein Netzwerkprotokoll wahrscheinlich schon der richtige Typ. Um ein händisches Umschreiben wirst Du aber nicht drumrum kommen. Blind aber irgendwelche encodings einzufügen ist aber der falsche Weg. Zum Schluß hast Du dann ein unwartbares Durcheinander von Strings und Bytes.
Thomas_W123
User
Beiträge: 8
Registriert: Freitag 23. Juli 2010, 16:49

Das mit dem Durcheinander merke ich.
Das Problem ist aber, dass ein Parameter mal ein string ist, und mal z.B. auch wieder ein array objekt. Und das array-Modul in Python 2 hat wohl alles ohne Probleme "gefressen". Wahrscheinlich ist das der Grund warum Python 2 immer noch gerne für quick&dirty Hacks verwendet wird.

Zumindest ist das Modul das ich verwenden will nicht von mir entwickelt, darum kann ich gar nicht überblicken wo ich was anpassen muss damit es wieder funktioniert. Da ich aber sicher nicht der erste bin der sowas von 2 nach 3 konvertieren will, dachte ich mir evtl. gibt es irgendwo ein fertiges array Modul was eben unter 3 genauso funktioniert wie unter 2, eben mit fixem encoding wie z.B. ascii (hat sich bisher auch keiner drum gekümmert).
BlackJack

@Thomas_W123: Das ist etwas das geht schlicht nicht automatisch, da muss ein Mensch ran und entscheiden ob etwas Bytes oder eine echte Zeichenkette ist und entsprechend konvertieren falls nötig. Einfach ASCII annehmen geht ziemlich sicher nicht falls es sich tatsächlich um beliebige Binärdaten handelt, denn mit ASCII kann man ja so gar nicht den Wertebereich von Bytes abdecken.
Thomas_W123
User
Beiträge: 8
Registriert: Freitag 23. Juli 2010, 16:49

Habs glaub ich soweit hinbekommen.

Ich habe die Vorkommen von "array.array('c')" durch "bytearray()" ersetzt.
Außerdem die Längenabfragen jedes Buffers von "buffer.buffer_info()[1]" durch "len(buffer)" ersetzt.

An der Stelle wo 'echte' Strings ins Spiel kommen, habe ich eine Typabfrage eingebaut. So in der Art:

Code: Alles auswählen

if type(data) is str:
    buf.extend(str.encode(data))
else:
    buf.extend(data)
In dem Netzwerkprotokoll ist kein Unicode zugelassen, darum sollte das mit dem einfachen encode passen denke ich mal. Wenn einer Umlaute reingibt, hat er eben Pech gehabt wenn es nicht funktioniert ;-)
BlackJack

@Thomas_W123: Der Typtest ist unschön und das kodieren auf *diese* Weise ebenfalls. Besser wäre es mit `isinstance()` zu prüfen und die Methode auf dem Objekt aufzurufen statt ”statisch” den `str`-Typ zu verwenden.
Thomas_W123
User
Beiträge: 8
Registriert: Freitag 23. Juli 2010, 16:49

Danke für den Hinweis. Musste mich erstmal einlesen wo da der Unterschied ist.

Habs jetzt so

Code: Alles auswählen

if isinstance(data, str):
    buf.extend(data.encode())
else:
    buf.extend(data)
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@Thomas_W123: wenn das schon nötig ist, wäre es besser, das in eine eigene Funktion auszulagern,

Code: Alles auswählen

def to_bytes(data):
    return data.encode() if hasattr(data, "encode") else data

buf.extend(to_bytes(data))
obwohl man solche Zweideutigkeiten vermeiden sollte. Um welches Netzwerkprotokoll handelt es sich denn? Dort muß doch geregelt sein, mit welchem Encoding Strings zu übertragen sind.
Antworten