问题描述
例如,假设我有一个用于迭代文件内记录的类:
class MySpecialFile:
...
def reset(self):
self._handle.seek(0)
def __iter__(self):
self.reset()
return self
编辑:
几个月后我才读到这个问题,我问它,觉得有点愚蠢:)。
正如下面的答案中所写,具有副作用的__iter__
方法是一件坏事。
如果你想多次迭代你的对象,那么你只需要在每次调用__iter__
时返回一个新的迭代器对象:
class IterableFile:
def __iter__(self):
return FileIterator(self)
回想起来,这很明显,这也是我现在觉得自己很傻的原因,我想。 不确定我在想什么,但我认为我不愿意拥有两个单独的类的原因是每个新的迭代器都需要创建一个新的文件处理程序(我的 SpecialFile 类只是文本/二进制文件顶部的一个接口)这让我当时觉得“过度”和奇怪。
1楼
iter
预计没有副作用。
通过违反这个假设,你的代码会破坏各种各样的东西。
例如,一个事物是否可迭代的标准测试:
try:
iter(thing)
except TypeError:
do_whatever()
将重置您的文件。 同样, :
def consume(iterator, n=None):
"Advance the iterator n-steps ahead. If n is None, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
将产生不正确的文件位置,而不是在consume(your_file, n)
之后推进n
条记录。
在循环之前用next
跳过前几条记录也会失败:
f = MySpecialFile(whatever)
next(f) # Skip a header, or try, anyway.
for record in f:
# We get the header anyway.
uhoh()
2楼
任何破坏语言结构预期流程的东西都是危险信号,比“代码异味”更糟糕。 这不是 Python 特有的; 它适用于任何语言或系统。
但是,请记住对“小头脑的妖精”的严格要求:
-
您的
reset
是否改善了程序流程? - 生成的代码是否易于阅读和理解?
如果你已经为那些必须理解和维护它的人——包括你未来的自己——覆盖了这些,那么reset
可能是一个很好的做法。
我持怀疑态度,但我在工作中看到过这样的情况。
旁注:为什么第一次构造迭代器时需要reset
迭代器?