将文件对象子类化为" fake"它作为一个可迭代的 - Python

时间:2018-02-12 10:04:36

标签: python oop file-io iterable python-collections

我的想法是摆脱用户如何不断使用seek(0)重置文本文件读取。

相反,我尝试创建MyReader collections.Iterator,然后使用.reset()替换seek(0),然后继续它通过保留self.iterable对象而持续产生的位置。

class MyReader(collections.Iterator):
    def __init__(self, filename):
        self.filename = filename
        self.iterable = self.__iterate__()

    def __iterate__(self):
        with open(self.filename) as fin:
            for line in fin:
                yield line.strip()

    def __iter__(self):
        for line in self.iterable:
            yield line

    def __next__(self):
        return next(self.iterable)

    def reset(self): 
        self.iterable = self.__iterate__()

用法如下:

$ cat english.txt
abc
def
ghi
jkl

$ python

>>> data = MyReader('english.txt')
>>> print(next(data))
abc
>>> print(next(data))
def
>>> data.reset()
>>> print(next(data))
abc

我的问题是这是否已经存在于Python-verse某处? Esp。如果已经有一个像这样的本地对象,我想避免重新发明轮子=)

如果它不存在? 该对象看起来有点单声道吗?因为它说它是一个迭代器,但真正的迭代器实际上是self.iterable而其他函数围绕着它来做&#34 ;重置&#34 ;.

2 个答案:

答案 0 :(得分:3)

我认为这取决于你的实际情况。假设你只想摆脱file.seek(0),那就简单了:

class MyReader:
    def __init__(self, filename, mode="r"):
        self.file = open(filename, mode)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.close()

    def __iter__(self):
        self.file.seek(0)
        for line in self.file:
            yield line.strip()

    def close(self):
        self.file.close()

您甚至可以像普通的上下文管理器一样使用它:

with MyReader("a.txt") as a:
    for line in a:
        print(line)
    for line in a:
        print(line)

输出:

sdfas
asdf
asd
fas
df
asd
f
sdfas
asdf
asd
fas
df
asd
f

答案 1 :(得分:1)

我对你的MyReader课程有一些批评。我 要发布一个context manager的替代品,但是Sraw打败了我。 ;)

您不应该使用以__iterate__等双下划线开头和结尾的名称。这些名称基本上是为语言实现者保留的,如果将一种官方的__iterate__魔术方法添加到您的代码将破坏的语言中。如果您想要私有方法,可以将其命名为_iterate

__iterate__方法存在一些问题:只有在为当前with完全读取文件时才会退出其self.iterable块,因此MyReader实例重置然后你有一个旧的打开文件,消耗文件描述符。当然,当程序退出时(或者你删除MyReader实例),它最终会被关闭,但它是混乱的恕我直言。

另外,我对yield line.strip()并不满意。当然,大多数情况下,当您阅读文本文件时,它很方便,但在某些情况下,调用者可能希望查看任何前导或尾随空格,并且您已将该选项远离它们。

顺便说一句,__iter__方法是多余的:如果你消除了这种方法,你的类仍然会做它应该做的事情。