Backporting Python 3 geöffnet (Kodierung = "utf-8") nach Python 2

152

Ich habe eine Python-Codebasis, die für Python 3 erstellt wurde und den Python 3-Stil open () mit dem Codierungsparameter verwendet:

https://github.com/miohtama/vvv/blob/master/vvv/textlineplugin.py#L47

    with open(fname, "rt", encoding="utf-8") as f:

Jetzt möchte ich diesen Code auf Python 2.x zurückportieren, damit ich eine Codebasis habe, die mit Python 2 und Python 3 funktioniert.

Was ist die empfohlene Strategie, um open()Unterschiede und fehlende Codierungsparameter zu umgehen?

Könnte ich einen open()Dateihandler im Python 3- Stil haben, der Bytestrings streamt, sodass er sich wie Python 2 verhält open()?

Mikko Ohtamaa
quelle

Antworten:

176

1. So erhalten Sie einen Codierungsparameter in Python 2:

Wenn Sie nur Python 2.6 und 2.7 unterstützen müssen, können Sie io.openstattdessen verwenden open. ioist das neue io-Subsystem für Python 3 und existiert auch in Python 2.6 und 2.7. Bitte beachten Sie, dass Python 2.6 (sowie 3.0) nur in Python implementiert und sehr langsam ist. Wenn Sie also beim Lesen von Dateien Geschwindigkeit benötigen, ist dies keine gute Option.

Wenn Sie Geschwindigkeit benötigen und Python 2.6 oder früher unterstützen müssen, können Sie codecs.openstattdessen verwenden. Es hat auch einen Codierungsparameter und ist ziemlich ähnlich, io.openaußer dass es Zeilenenden unterschiedlich behandelt.

2. So erhalten Sie einen open()Dateihandler im Python 3- Stil, der Bytestrings überträgt:

open(filename, 'rb')

Beachten Sie das 'b', was 'binär' bedeutet.

Lennart Regebro
quelle
11
Das 'b' bedeutet eigentlich Binärmodus, nicht Bytes. Siehe docs.python.org/3/library/functions.html#open .
pmdarrow
7
@pmdarrow Das Gleiche in diesem Fall, aber genau genommen ja.
Lennart Regebro
Ich bin auf das Problem gestoßen, dass Sie für Option 2 keinen regulären Ausdruck über einen Bytestream ausführen können;)
Jonathan Komar
3
@ macmadness86 Sie müssen einen Byte-Regexp-Ausdruck verwenden.
Lennart Regebro
4
Ein Hinweis aus dem Portierungs-Howto: "Machen Sie sich keine Gedanken über die veraltete Praxis der Verwendung von codecs.open (), da dies nur erforderlich ist, um die Kompatibilität mit Python 2.5 zu gewährleisten." docs.python.org/3/howto/pyporting.html
Al Sweigart
65

Meiner Ansicht nach

from io import open

sollte tun.

mfussenegger
quelle
7
Ich denke, Lennarts Antwort unten ist viel besser, da sie mehr Erklärungen und die Einschränkung enthält, dass das io-Modul in 2.x langsam ist, zusammen mit dem Vorschlag, codecs.open zu verwenden.
GPS
2
Was passiert, wenn ich from io import openin Python 3 verwende? Die Leistung ist mir derzeit egal.
Matth
8
@matth In Python3 ist open from io ein Alias ​​für das integrierte open. Siehe docs.python.org/3/library/io.html?highlight=io#io.open
mfussenegger
20

Hier ist eine Möglichkeit:

with open("filename.txt", "rb") as f:
    contents = f.read().decode("UTF-8")
Flimm
quelle
4
Dies funktioniert offensichtlich nicht, wenn Sie andere Pläne hatten fürf
user5359531
8

Dies kann den Trick tun:

import sys
if sys.version_info[0] > 2:
    # py3k
    pass
else:
    # py2
    import codecs
    import warnings
    def open(file, mode='r', buffering=-1, encoding=None,
             errors=None, newline=None, closefd=True, opener=None):
        if newline is not None:
            warnings.warn('newline is not supported in py2')
        if not closefd:
            warnings.warn('closefd is not supported in py2')
        if opener is not None:
            warnings.warn('opener is not supported in py2')
        return codecs.open(filename=file, mode=mode, encoding=encoding,
                    errors=errors, buffering=buffering)

Dann können Sie Ihren Code auf python3-Weise behalten.

Beachten Sie, dass einige APIs wie newline, closefd, openerfunktionieren nicht

user2395922
quelle
1
Sie können den Zustand umkehren, um dies zu vermeiden pass.
Bfontaine
2

Wenn Sie verwenden six, können Sie dies versuchen, indem Sie die neueste Python 3-API verwenden und in beiden Python 2/3 ausführen:

import six

if six.PY2:
    # FileNotFoundError is only available since Python 3.3
    FileNotFoundError = IOError
    from io import open

fname = 'index.rst'
try:
    with open(fname, "rt", encoding="utf-8") as f:
        pass
        # do_something_with_f ...
except FileNotFoundError:
    print('Oops.')

Und die Aufgabe der Python 2-Unterstützung löscht nur alles, was damit zu tun hat six.

YaOzI
quelle