Backporting Python 3 terbuka (encoding = "utf-8") ke Python 2

152

Saya memiliki basis kode Python, dibuat untuk Python 3, yang menggunakan Python 3 style open () dengan parameter penyandian:

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

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

Sekarang saya ingin backport kode ini ke Python 2.x, sehingga saya akan memiliki basis kode yang berfungsi dengan Python 2 dan Python 3.

Apa strategi yang disarankan untuk mengatasi open()perbedaan dan kurangnya parameter pengkodean?

Bisakah saya memiliki open()penangan file gaya Python 3 yang stream bytestrings, sehingga akan bertindak seperti Python 2 open()?

Mikko Ohtamaa
sumber

Jawaban:

176

1. Untuk mendapatkan parameter enkode dalam Python 2:

Jika Anda hanya perlu untuk mendukung Python 2,6 dan 2,7 Anda dapat menggunakan io.openbukan open. ioadalah subsistem io baru untuk Python 3, dan itu ada di Python 2,6 ans 2.7 juga. Perlu diketahui bahwa dalam Python 2.6 (dan juga 3.0) ini diterapkan murni dalam python dan sangat lambat, jadi jika Anda memerlukan kecepatan dalam membaca file, itu bukan pilihan yang baik.

Jika Anda membutuhkan kecepatan, dan Anda harus mendukung Python 2.6 atau yang lebih lama, Anda dapat menggunakannya codecs.open. Ini juga memiliki parameter pengkodean, dan sangat mirip dengan io.openkecuali itu menangani akhir baris berbeda.

2. Untuk mendapatkan open()penangan file gaya Python 3 yang mengalirkan bytestrings:

open(filename, 'rb')

Perhatikan 'b', yang berarti 'biner'.

Lennart Regebro
sumber
11
'B' sebenarnya berarti mode biner, bukan byte. Lihat docs.python.org/3/library/functions.html#open .
pmdarrow
7
@pmdarrow Hal yang sama dalam hal ini, tetapi secara tegas, ya.
Lennart Regebro
Saya mengalami masalah bahwa Anda tidak dapat menjalankan regex melalui byte stream untuk opsi 2;)
Jonathan Komar
3
@ macmadness86 Anda perlu menggunakan ekspresi regexp byte.
Lennart Regebro
4
Catatan dari porting howto: "Jangan repot-repot dengan praktik usang menggunakan codecs.open () karena itu hanya diperlukan untuk menjaga kompatibilitas dengan Python 2.5." docs.python.org/3/howto/pyporting.html
Al Sweigart
65

kupikir

from io import open

harus dilakukan.

mfussenegger
sumber
7
Saya pikir respons Lennart di bawah ini jauh lebih baik karena memberikan lebih banyak penjelasan dan peringatan tentang modul io yang lambat di 2.x bersama dengan saran untuk menggunakan codecs.open.
gps
2
Apa yang terjadi jika saya menggunakan from io import openPython 3? Saya tidak peduli dengan kinerja saat ini.
matth
8
@matth Dalam python3 open from io adalah alias untuk built-in open. Lihat docs.python.org/3/library/io.html?highlight=io#io.open
mfussenegger
21

Ini salah satu caranya:

with open("filename.txt", "rb") as f:
    contents = f.read().decode("UTF-8")
Flimm
sumber
4
ini jelas tidak berfungsi jika Anda memiliki rencana berbeda untukf
user5359531
8

Ini dapat melakukan trik:

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)

Kemudian Anda dapat membuat kode Anda dengan cara python3.

Perhatikan bahwa beberapa API suka newline , closefd, openertidak bekerja

pengguna2395922
sumber
1
Anda dapat membalik kondisi untuk menghindari itu pass.
bfontaine
2

Jika Anda menggunakan six, Anda dapat mencoba ini, dengan yang menggunakan API Python 3 terbaru dan dapat berjalan di kedua 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.')

Dan, dukungan Python 2 ditinggalkan hanya menghapus semua yang berhubungan dengan six.

YaOzI
sumber