Бэкпортирование открытого Python 3 (encoding = «utf-8») в Python 2


152

У меня есть кодовая база Python, созданная для Python 3, которая использует стиль Python 3 open () с параметром кодирования:

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

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

Теперь я хотел бы перенести этот код в Python 2.x, чтобы у меня была кодовая база, которая работает с Python 2 и Python 3.

Какова рекомендуемая стратегия для обхода open()различий и отсутствия параметра кодирования?

Могу ли я иметь open()обработчик файлов в стиле Python 3, который передает потоковые строки, чтобы он работал как Python 2 open()?

Ответы:


177

1. Чтобы получить параметр кодирования в Python 2:

Если вам нужно только поддерживать Python 2.6 и 2.7, вы можете использовать io.openвместо open. ioэто новая подсистема io для Python 3, и она также существует в Python 2,6 и 2.7. Помните, что в Python 2.6 (а также 3.0) он реализован исключительно на python и очень медленный, поэтому, если вам нужна скорость чтения файлов, это не очень хороший вариант.

Если вам нужна скорость и вам нужна поддержка Python 2.6 или более ранней версии, вы можете использовать codecs.openвместо этого. У него также есть параметр кодирования, и он очень похож, за io.openисключением того, что он обрабатывает окончания строк по-разному.

2. Чтобы получить open()обработчик файлов в стиле Python 3, который транслирует строки байтов:

open(filename, 'rb')

Обратите внимание на «b», что означает «двоичный».


11
'B' фактически означает двоичный режим, а не байты. См. Docs.python.org/3/library/functions.html#open .
pmdarrow

7
@pmdarrow То же самое в этом случае, но, строго говоря, да.
Леннарт Регебро

Я столкнулся с проблемой, что вы не можете запустить регулярное выражение через поток байтов для варианта 2;)
Джонатан Комар

3
@ macmadness86 Вы должны использовать выражение для выражения регулярных выражений байтов.
Леннарт Регебро

4
Примечание от инструкции по переносу: «Не беспокойтесь об устаревшей практике использования codecs.open (), поскольку это необходимо только для обеспечения совместимости с Python 2.5». docs.python.org/3/howto/pyporting.html
Аль Свейгарт,

65

думаю

from io import open

стоит сделать.


7
Я думаю, что ответ Леннарта, представленный ниже, гораздо лучше, так как он дает больше объяснений и предостережения о медленном модуле io в 2.x вместе с предложением использовать codecs.open.
GPS

2
Что произойдет, если я использую from io import openв Python 3? Я не забочусь о производительности в настоящее время.
Matth

8
@matth В python3 open от io есть псевдоним для встроенного open. См. Docs.python.org/3/library/io.html?highlight=io#io.open
mfussenegger

21

Вот один из способов:

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

4
это, очевидно, не работает, если у вас были другие планыf
user5359531

8

Это может сделать трюк:

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)

Тогда вы можете сохранить свой код в стиле python3.

Обратите внимание , что некоторые интерфейсы нравится newline, closefd, openerне работают


1
Вы можете отменить условие, чтобы избежать этого pass.
bfontaine

2

Если вы используете six, вы можете попробовать это, используя последний API Python 3 и может работать как в 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.')

А отказ от поддержки Python 2 - это просто удаление всего, что связано с six.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.