Backporting Python 3 abierto (codificación = "utf-8") a Python 2


152

Tengo una base de código Python, creada para Python 3, que usa el estilo Python 3 open () con el parámetro de codificación:

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

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

Ahora me gustaría exportar este código a Python 2.x, para tener una base de código que funcione con Python 2 y Python 3.

¿Cuál es la estrategia recomendada para solucionar las open()diferencias y la falta de parámetros de codificación?

¿Podría tener un open()controlador de archivo de estilo Python 3 que transmita cadenas de bytes, para que actúe como Python 2 open()?

Respuestas:


176

1. Para obtener un parámetro de codificación en Python 2:

Si solo necesita admitir Python 2.6 y 2.7, puede usarlo en io.openlugar de open. ioes el nuevo subsistema io para Python 3, y también existe en Python 2,6 y 2.7. Tenga en cuenta que en Python 2.6 (así como en 3.0) se implementa únicamente en Python y muy lento, por lo que si necesita velocidad para leer archivos, no es una buena opción.

Si necesita velocidad, y necesita admitir Python 2.6 o anterior, puede usar codecs.openen su lugar. También tiene un parámetro de codificación, y es bastante similar, io.openexcepto que maneja los finales de línea de manera diferente.

2. Para obtener un open()controlador de archivos de estilo Python 3 que transmita cadenas de bytes:

open(filename, 'rb')

Tenga en cuenta la 'b', que significa 'binario'.


11
La 'b' en realidad significa modo binario, no bytes. Ver docs.python.org/3/library/functions.html#open .
pmdarrow

77
@pmdarrow Lo mismo en este caso, pero estrictamente hablando, sí.
Lennart Regebro

Me encontré con el problema de que no se puede ejecutar regex en una secuencia de bytes para la opción 2;)
Jonathan Komar

3
@ macmadness86 Debe usar una expresión de expresión regular de bytes.
Lennart Regebro

44
Una nota del manual de portabilidad: "No te molestes con la práctica desactualizada de usar codecs.open () ya que eso solo es necesario para mantener la compatibilidad con Python 2.5". docs.python.org/3/howto/pyporting.html
Al Sweigart

65

Yo creo que

from io import open

debería hacer.


77
Creo que la respuesta de Lennart a continuación es mucho mejor, ya que proporciona más explicaciones y la advertencia de que el módulo io es lento en 2.x junto con la sugerencia de usar codecs.open.
GPS

2
¿Qué pasa si lo uso from io import openen Python 3? Actualmente no me importa el rendimiento.
Mat

8
@matth En python3 open from io es un alias para el open incorporado. Ver docs.python.org/3/library/io.html?highlight=io#io.open
mfussenegger el

21

Aquí hay una manera:

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

44
esto obviamente no funciona si tuvieras planes diferentes paraf
user5359531

8

Esto puede hacer el truco:

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)

Entonces puede mantener su código de la manera python3.

Tenga en cuenta que algunas API como newline, closefd, openerno funcionan


1
puedes revertir la condición para evitar eso pass.
bfontaine

2

Si está utilizando six, puede probar esto, mediante el cual utiliza la última API de Python 3 y puede ejecutarse en 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.')

Y, el abandono del soporte de Python 2 es solo eliminar todo lo relacionado con six.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.