我的想法是摆脱用户如何不断使用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 ;.
答案 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__
方法是多余的:如果你消除了这种方法,你的类仍然会做它应该做的事情。