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.