Backporting Python 3 aperto (codifica = "utf-8") su Python 2


152

Ho una base di codice Python, costruita per Python 3, che utilizza lo stile Python 3 open () con il parametro di codifica:

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

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

Ora vorrei eseguire il backport di questo codice su Python 2.x, in modo da avere una base di codice che funzioni con Python 2 e Python 3.

Qual è la strategia consigliata per aggirare le open()differenze e la mancanza di parametri di codifica?

Potrei avere un open()gestore di file in stile Python 3 che trasmette in streaming bytestrings, quindi si comporterebbe come Python 2 open()?

Risposte:


176

1. Per ottenere un parametro di codifica in Python 2:

Se hai solo bisogno di supportare Python 2.6 e 2.7 puoi usare io.openinvece di open. ioè il nuovo sottosistema io per Python 3 ed esiste anche in Python 2,6 e 2,7. Tieni presente che in Python 2.6 (oltre a 3.0) è implementato esclusivamente in Python e molto lento, quindi se hai bisogno di velocità nella lettura dei file, non è una buona opzione.

Se hai bisogno di velocità e devi supportare Python 2.6 o precedente, puoi codecs.openinvece usare . Ha anche un parametro di codifica ed è abbastanza simile ad io.openeccezione del fatto che gestisce le terminazioni di riga in modo diverso.

2. Per ottenere un open()gestore di file in stile Python 3 che trasmette i bytestrings:

open(filename, 'rb')

Nota 'b', che significa 'binario'.


11
La "b" in realtà significa modalità binaria, non byte. Vedi docs.python.org/3/library/functions.html#open .
pmdarrow

7
@pmdarrow Stessa cosa in questo caso, ma in senso stretto, sì.
Lennart Regebro,

Ho riscontrato il problema che non è possibile eseguire regex su un flusso di byte per l'opzione 2;)
Jonathan Komar,

3
@ macmadness86 È necessario utilizzare un'espressione regexp di byte.
Lennart Regebro,

4
Una nota dal porting howto: "Non preoccuparti della pratica obsoleta dell'uso di codecs.open () poiché è necessario solo per mantenere la compatibilità con Python 2.5." docs.python.org/3/howto/pyporting.html
Al Sweigart

65

penso

from io import open

dovresti ... dovrebbe.


7
Penso che la risposta di Lennart di seguito sia molto migliore in quanto fornisce ulteriori spiegazioni e la precisazione che il modulo io è lento in 2.x insieme al suggerimento di usare codecs.open.
gps,

2
Cosa succede se uso from io import openin Python 3? Non mi interessa per le prestazioni al momento.
Matth,

8
@matth In python3 open di io è un alias per open incorporato. Vedi docs.python.org/3/library/io.html?highlight=io#io.open
mfussenegger

21

Ecco un modo:

with open("filename.txt", "rb") as f:
    contents = f.read().decode("UTF-8")

4
questo ovviamente non funziona se avevi piani diversi perf
user5359531

8

Questo può fare il trucco:

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)

Quindi puoi mantenere il tuo codice nel modo python3.

Si noti che alcune API piace newline, closefd, openernon lavoro


1
puoi invertire la condizione per evitarlo pass.
bfontaine,

2

Se lo stai utilizzando six, puoi provare questo, utilizzando il più recente API Python 3 e può essere eseguito in entrambi Python 2/3:

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.')

E, l'abbandono del supporto di Python 2 sta semplicemente cancellando tutto ciò che riguarda six.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.