将Python 2.x文件像对象一样移植到Python 3

时间:2013-03-25 10:50:58

标签: python file python-3.x io porting

我正致力于改进{3.}}的Python 3.X支持。它是文件系统的抽象。每个文件系统对象都有一个open方法,它返回一个类似文件的对象。

我面临的问题是open方法在Python 2.X上运行open,但我希望它像io.open一样工作,返回一些二进制或文本模式流。

我可以使用的方法是获取类似Python 2.X文件的对象,并返回一个适当的io流对象,该对象读取/写入底层文件类对象(但如果需要,则处理缓冲/ unicode等) )。

我在考虑以下内容:

def make_stream(file_object, mode, buffering, encoding):
    # return a io instance

我看不出使用stdlib做任何直接的方法。但它让我觉得io模块必须在引擎盖下做,因为它是一个提供缓冲/ unicode功能的软件层。

1 个答案:

答案 0 :(得分:1)

Python 2也包含相同的io library

使用from io import open在Python版本中使用相同的工作。

然后,您的API应提供使用open()类库提供相同功能的open()等效项(称为make_stream()io)。

您需要做的就是创建一个实现io.RawIOBase ABC的类,然后使用库提供的其他类来根据需要添加缓冲和文本处理 < / EM>:

import io

class MyFileObjectWrapper(io.RawIOBase):
    def __init__(self, *args):
        # do what needs done

    def close(self):
        if not self.closed:
            # close the underlying file
        self.closed = True

    # ... etc for what is needed (e.g. def read(self, maxbytes=None), etc.

def open(fileobj, mode='r', buffering=-1, encoding=None, errors=None, newline=None):
    # Mode parsing and validation adapted from the io/_iomodule.c module
    reading, writing, appending, updating = False
    text, binary, universal = False

    for c in mode:
        if c == 'r':
            reading = True;
            continue
        if c == 'w':
            writing = True;
            continue
        if c == 'a':
            appending = True;
            continue
        if c == '+':
            updating = True;
            continue
        if c == 't':
            text = True;
            continue
        if c == 'b':
            binary = True;
            continue
        if c == 'U':
            universal = reading = True;
            continue
        raise ValueError('invalid mode: {!r}'.format(mode))

    rawmode = []
    if reading:   rawmode.append('r')
    if writing:   rawmode.append('w')
    if appending: rawmode.append('a')
    if updating:  rawmode.append('+')
    rawmode = ''.join(rawmode)

    if universal and (writing or appending):
        raise ValueError("can't use U and writing mode at once")

    if text and binary) {
        raise ValueError("can't have text and binary mode at once")

    if reading + writing + appending > 1:
        raise ValueError("must have exactly one of read/write/append mode")

    if binary
        if encoding is not None:
            raise ValueError("binary mode doesn't take an encoding argument")
        if errors is not None:
            raise ValueError("binary mode doesn't take an errors argument")
        if newline is not None:
            raise ValueError("binary mode doesn't take a newline argument")

    raw = MyFileObjectWrapper(fileobj)

    if buffering == 1:
        buffering = -1
        line_buffering = True
    else:
        line_buffering = False

    if buffering < 0:
        buffering = SOME_SUITABLE_DEFAULT

    if not buffering
        if not binary:
            raise ValueError("can't have unbuffered text I/O")

        return raw

    if updating:
        buffered_class = io.BufferedRandom
    elif writing or appending:
        buffered_class = io.BufferedWriter
    elif reading:
        buffered_class = io.BufferedReader

    buffer = buffered_class(raw, buffering)

    if binary:
        return buffer

    return io.TextIOWrapper(buffer, encoding, errors, newline, line_buffering)

上面的代码主要是从Modules/_io/_iomodule.c io_open function改编而来,但原始文件对象被MyFileObjectWrapper ABC的io.RawIOBase子类替换。