Бэкпортирование открытого 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

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

mfussenegger
источник
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не работают

user2395922
источник
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.

YaOzI
источник