一个“类似文件”的对象的最小实现?

huangapple go评论76阅读模式
英文:

Minimal implementation of a "file-like" object?

问题

我想创建一个类似文件的对象,以便传递给另一个模块。我不知道那个模块是否会调用read()或者readline()或者两者都会调用。如果我要继承io.IOBase,然后只实现read(),那是否足够,即使客户端调用readline()呢?

奖励问题:如果我的类将以文本模式打开,那么我需要实现的最小部分是什么,以便让超类处理Unicode解码?

(这将是一个仅用于输入的类。)

元信息:我知道我可以只编写所有方法,然后查看实际调用了哪些方法,但我想要更加“未来可靠”,按照实际规范编写代码,而不是尝试各种方法来查看它们是否有效,然后在未来某一天出现问题。

英文:

I want to create a file-like object to be passed to another module. I don't know if that other module will be calling read() or readline() or both. If I were to subclass say io.IOBase and just implement read() would that be sufficient, even if the client is calling readline()?

Bonus question: if my class will be opened in text mode, what's the minimum I can implement to let the superclass handle the unicode decoding?

(This will be an input-only class.)

Meta: I know I could just write all the methods and see what actually gets called, but I'd like to be a bit "future proof" and write to the actual specs, instead of trying things to see if they work, and then having them break in the future someday.

答案1

得分: 3

从经验上看,实现read将足够。

至于文本模式,您只需使用TextIOWrapper(技术上应该与BufferedIOBase一起使用,但看起来与IOBase也能正常工作)。

import io

class FooIO(io.IOBase):
    def __init__(self, buffer):
        self.buffer = buffer
        self.pos = 0

    def rewind(self):
        self.pos = 0

    def readable(self) -> bool:
        return True

    def read(self, size=-1):
        if size == -1:
            size = len(self.buffer) - self.pos
        data = self.buffer[self.pos:self.pos + size]
        self.pos += size
        return data

f = FooIO(b"hello\nworld\nthis\nis\na\ntest")
for x in range(7):
    print(x, f.readline())
f.rewind()

tiow = io.TextIOWrapper(f)
for x in range(7):
    print(x, repr(tiow.readline()))

打印结果如下:

0 b'hello\n'
1 b'world\n'
2 b'this\n'
3 b'is\n'
4 b'a\n'
5 b'test'
6 b''
0 'hello\n'
1 'world\n'
2 'this\n'
3 'is\n'
4 'a\n'
5 'test'
6 ''
英文:

Empirically, implementing read will be enough.

As for text mode, you'd want to just use TextIOWrapper (which technically is meant to be used with a BufferedIOBase, but it looks like things work with IOBase too).

import io


class FooIO(io.IOBase):
    def __init__(self, buffer):
        self.buffer = buffer
        self.pos = 0

    def rewind(self):
        self.pos = 0

    def readable(self) -> bool:
        return True

    def read(self, size=-1):
        if size == -1:
            size = len(self.buffer) - self.pos
        data = self.buffer[self.pos:self.pos + size]
        self.pos += size
        return data


f = FooIO(b"hello\nworld\nthis\nis\na\ntest")
for x in range(7):
    print(x, f.readline())
f.rewind()

tiow = io.TextIOWrapper(f)
for x in range(7):
    print(x, repr(tiow.readline())))

prints out

0 b'hello\n'
1 b'world\n'
2 b'this\n'
3 b'is\n'
4 b'a\n'
5 b'test'
6 b''
0 'hello\n'
1 'world\n'
2 'this\n'
3 'is\n'
4 'a\n'
5 'test'
6 ''

huangapple
  • 本文由 发表于 2023年1月9日 01:18:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/75049862.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定