【问题标题】:Porting a Python 2.x file like object to Python 3将 Python 2.x 文件(如对象)移植到 Python 3
【发布时间】:2013-03-25 10:50:58
【问题描述】:

我正在努力改进 Python 3.X 对 PyFilesystem 的支持。它是文件系统的抽象。每个文件系统对象都有一个 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 功能的软件层。

【问题讨论】:

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


    【解决方案1】:

    Python 2 也包含相同的 io library

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

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

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

    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,但原始文件对象被io.RawIOBase ABC的MyFileObjectWrapper子类替换。

    【讨论】:

    • 是的,我知道。从 Python 2.6 开始。但是我仍然需要为类文件对象提供 io 接口。这些不是实际的文件对象。数据来自各种不同的来源。
    • @WillMcGugan:是的,我误解了你的意思。 ioopen 函数只是一个工厂。它返回一系列类的实例。这没什么神奇的,你可以在自己的库中实现同样的东西。
    • @WillMcGugan:当然,您可以使用io 库抽象基类作为模板,以使您的对象符合预期。如果您提供自己的原始文件对象实现,您还可以重用 io 缓冲区和文本包装类。
    • 我曾考虑过这一点,但为每种模式/缓冲组合提供 shill 类似乎需要做很多工作。猜猜我希望有更简单的东西。
    • 您也可以参考2.6 implementation。它在 2.7 中被移植到 C。
    猜你喜欢
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 2020-12-28
    • 1970-01-01
    • 2023-03-13
    • 2013-01-30
    相关资源
    最近更新 更多