Зворотний порт Python 3 відкритий (encoding = "utf-8") на Python 2


152

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

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()?

Відповіді:


176

1. Щоб отримати параметр кодування в Python 2:

Якщо вам потрібно підтримувати лише Python 2.6 та 2.7, ви можете використовувати io.openзамість них open. ioє новою підсистемою io для Python 3, і вона існує і в Python 2,6 ans 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
Al Sweigart

65

Я думаю

from io import open

повинен робити.


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

2
Що станеться, якщо я використовую from io import openв Python 3? Наразі я не дбаю про продуктивність.
матч

8
@matth У python3 open from io - псевдонім для вбудованого відкритого. Дивіться 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.