Backporting Python 3 เปิด (การเข้ารหัส =“ utf-8”) ถึง Python 2


152

ฉันมี Python codebase สร้างขึ้นสำหรับ Python 3 ซึ่งใช้ Python 3 style open () พร้อมพารามิเตอร์การเข้ารหัส:

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

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

ตอนนี้ฉันต้องการ backport รหัสนี้เป็น Python 2.x เพื่อที่ฉันจะได้ codebase ซึ่งทำงานกับ Python 2 และ Python 3

กลยุทธ์ที่แนะนำในการแก้ไขopen()ความแตกต่างและการขาดพารามิเตอร์การเข้ารหัสคืออะไร

ฉันขอใช้open()ตัวจัดการไฟล์สไตล์Python 3 ได้หรือไม่ซึ่งส่งกระแสข้อมูลทดสอบดังนั้นมันจะทำหน้าที่เหมือน Python 2 open()หรือไม่

คำตอบ:


176

1. วิธีรับพารามิเตอร์การเข้ารหัสใน Python 2:

หากคุณต้องการเพียงเพื่อสนับสนุนหลาม 2.6 และ 2.7 คุณสามารถใช้แทนio.open เป็นระบบย่อย io ใหม่สำหรับ Python 3 และมีอยู่ใน Python 2,6 ans 2.7 เช่นกัน โปรดทราบว่าใน Python 2.6 (เช่นเดียวกับ 3.0) มันถูกใช้งานใน Python และช้ามากดังนั้นหากคุณต้องการความเร็วในการอ่านไฟล์มันไม่ใช่ตัวเลือกที่ดีopenio

หากคุณต้องการความเร็วและคุณต้องรองรับ 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 สิ่งเดียวกันในกรณีนี้ แต่พูดอย่างเคร่งครัดใช่
Lennart Regebro

ฉันพบปัญหาที่คุณไม่สามารถเรียกใช้ regex ผ่านทาง byte stream สำหรับตัวเลือกที่ 2;)
Jonathan Komar

3
@ macmadness86 คุณต้องใช้นิพจน์ไบต์ regexp
Lennart Regebro

4
บันทึกจากการย้ายพอร์ตอย่างไร: "อย่ากังวลกับวิธีการใช้ตัวแปลงสัญญาณที่ล้าสมัยของ codecs.open () เนื่องจากจำเป็นสำหรับการทำงานร่วมกับ Python 2.5 เท่านั้น" docs.python.org/3/howto/pyporting.html
Al Sweigart

65

ฉันคิด

from io import open

ควรทำ.


7
ฉันคิดว่าการตอบสนองของ Lennart ด้านล่างนั้นดีกว่ามากเพราะให้คำอธิบายเพิ่มเติมและข้อควรระวังเกี่ยวกับโมดูล io นั้นช้าใน 2.x พร้อมกับคำแนะนำในการใช้ตัวแปลงสัญญาณ
gps

2
จะเกิดอะไรขึ้นถ้าฉันใช้from io import openใน Python 3 ฉันไม่สนใจประสิทธิภาพในขณะนี้
matth

8
@matth ใน python3 เปิดจาก 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

โปรดทราบว่า APIs บางอย่างเช่นnewline, closefd, openerจะไม่ได้ทำงาน


1
passคุณสามารถย้อนกลับอยู่ในสภาพที่จะหลีกเลี่ยงการว่า
bfontaine

2

หากคุณกำลังใช้sixคุณสามารถลองสิ่งนี้โดยใช้ Python 3 API ล่าสุดและสามารถทำงานได้ทั้ง 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.')

และงูหลาม 2 sixสนับสนุนละทิ้งเป็นเพียงการลบทุกอย่างที่เกี่ยวข้องกับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.