Backporting Python 3 mở (mã hóa = Thời gian utf-8) cho Python 2


152

Tôi có một cơ sở mã Python, được xây dựng cho Python 3, sử dụng kiểu open () của Python 3 với tham số mã hóa:

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

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

Bây giờ tôi muốn nhập mã này vào Python 2.x, để tôi có một cơ sở mã hoạt động với Python 2 và Python 3.

Chiến lược được đề xuất để khắc phục open()sự khác biệt và thiếu tham số mã hóa là gì?

Tôi có thể có open()trình xử lý tệp kiểu Python 3 để truyền phát bytestrings không, vì vậy nó sẽ hoạt động như Python 2 open()?

Câu trả lời:


176

1. Để có được một tham số mã hóa trong Python 2:

Nếu bạn chỉ cần hỗ trợ Python 2.6 và 2.7, bạn có thể sử dụng io.openthay vì open. iolà hệ thống con io mới cho Python 3 và nó cũng tồn tại trong Python 2,6 ans 2.7. Xin lưu ý rằng trong Python 2.6 (cũng như 3.0), nó được triển khai hoàn toàn bằng python và rất chậm, vì vậy nếu bạn cần tốc độ trong việc đọc tệp, thì đó không phải là một lựa chọn tốt.

Nếu bạn cần tốc độ và bạn cần hỗ trợ Python 2.6 trở về trước, bạn có thể sử dụng codecs.openthay thế. Nó cũng có một tham số mã hóa, và khá giống với io.openngoại trừ nó xử lý các kết thúc dòng khác nhau.

2. Để có được open()trình xử lý tệp kiểu Python 3 phát trực tiếp bytestrings:

open(filename, 'rb')

Lưu ý 'b', có nghĩa là 'nhị phân'.


11
'B' thực sự có nghĩa là chế độ nhị phân, không phải byte. Xem docs.python.org/3/l Library / fiances.html # open .
pmdarrow

7
@pmdarrow Điều tương tự trong trường hợp này, nhưng nói đúng ra là có.
Lennart Regebro

Tôi gặp vấn đề là bạn không thể chạy regex qua luồng byte cho tùy chọn 2;)
Jonathan Komar

3
@ macmadness86 Bạn cần sử dụng biểu thức regrec byte.
Lennart Regebro

4
Một lưu ý từ cách chuyển cổng: "Đừng bận tâm đến việc sử dụng codecs.open () đã lỗi thời vì điều đó chỉ cần thiết để duy trì khả năng tương thích với Python 2.5." docs.python.org/3/howto/pyporting.html
Al Sweigart

65

tôi nghĩ

from io import open

nên làm.


7
Tôi nghĩ rằng phản hồi của Lennart dưới đây tốt hơn nhiều vì nó cung cấp nhiều lời giải thích hơn và cảnh báo về mô-đun io bị chậm trong 2.x cùng với đề xuất sử dụng codec.open.
gps

2
Điều gì xảy ra nếu tôi sử dụng from io import opentrong Python 3? Tôi không quan tâm đến hiệu suất hiện tại.
matth

8
@matth Trong python3 mở từ io là một bí danh cho mở tích hợp. Xem docs.python.org/3/library/io.html?highlight=io#io.open
mfussenegger

21

Đây là một cách:

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

4
điều này rõ ràng không hoạt động nếu bạn có các kế hoạch khác nhau chof
user5359531

8

Điều này có thể thực hiện các mẹo:

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)

Sau đó, bạn có thể giữ cho bạn mã theo cách python3.

Lưu ý rằng một số hàm API thích newline, closefd, openerkhông làm việc


1
bạn có thể đảo ngược điều kiện để tránh điều đó pass.
bfontaine

2

Nếu bạn đang sử dụng six, bạn có thể thử điều này, bằng cách sử dụng API Python 3 mới nhất và có thể chạy trong cả 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.')

Và, từ bỏ hỗ trợ Python 2 chỉ là xóa mọi thứ liên quan đến six.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.